OAuth Applications
An OAuth application is the record that lets another program obtain access tokens from CityScreen Deals. CityScreen Deals is its own authorization server, so the application talks to your organization’s address directly and no outside identity provider is involved. Two flows are available. An application that works on its own behalf, such as a nightly synchronization job, uses client credentials. An application that works for an employee who allowed it, such as a dashboard or a web application with single sign-on, uses the authorization code flow with PKCE.
This function is licensed. If your organization’s license does not include it, contact CityScreen. The license entry is called "OAuth applications". Without it every OAuth endpoint on this page answers 404.
If the address of your organization is not an https address, the two discovery documents (see Endpoints) answer 503 Service Unavailable, because clients would send codes and tokens in clear text. Contact CityScreen in that case.
An employee who needs a token for a script of their own creates a personal access token, see Access Tokens and App Passwords.
Endpoints
All endpoints are on the address of your organization, for example https://deals.example.com.
The endpoints are at the root of the address, and only the REST API that the tokens open is under /api.
| Address | Method | Purpose |
|---|---|---|
|
GET |
Starts the authorization code flow in the employee’s browser. |
|
POST |
Issues access tokens for all grants and refreshes them. |
|
POST |
Revokes a token. |
|
POST |
Lets an application register itself, see Applications that register themselves. |
|
GET, POST |
Returns the claims of the employee for a token with the scope |
|
GET |
Publishes the keys that verify ID tokens. |
|
GET, POST |
Lets an application ask for the employee’s sign-out. |
|
GET |
Describe the server and all of the above for client libraries. |
Where applications are managed
Open Employees and then the OAuth applications tab. Viewing the tab needs the "OAuth applications" View permission, see Roles & Permissions.
The block at the top shows the "Issuer" and the "Discovery URL" of your organization, with a Copy discovery URL button. The table has these columns:
| Column | Content |
|---|---|
Name |
The name and description of the application, and "Registered by" with the employee who registered it. |
Client ID |
The client ID, with "Secret prefix", the first characters of the client secret. |
Roles |
The roles a client credentials application acts with. |
Last used |
When the application last obtained or used a token, or "Never". |
Authorized employees |
How many employees allowed the application. |
The buttons Create application, Edit, Regenerate secret, Delete and Rotate signing key appear when your role holds the matching permission. Rotate signing key is described in Single Sign-On with OpenID Connect.
Registering an Application
-
Open Employees > OAuth applications and press Create application.
-
Fill in the form described below.
-
Press Create.
-
Copy the client secret from the dialog "OAuth application created" before you press Done.
Registering needs the "OAuth applications" Create permission at organization scope. Before you register an application for someone who asks, confirm who is asking and which system will hold the client secret. A client credentials application acts with its roles without any employee.
| Field | What to enter |
|---|---|
Name |
Required, up to 255 characters. |
Description |
Up to 2000 characters. Say what the application does and who maintains it. |
Grant type |
Client credentials (the default), Authorization code, or both. The choice cannot be changed after creation. |
Issue refresh tokens |
Shown under Authorization code and on by default; the application then receives a refresh token with the access token. |
Public client (no client secret) |
Shown under Authorization code; a public client has no client secret and proves itself with PKCE. It cannot use client credentials, and this choice cannot be changed after creation. Choose it for applications that cannot keep a secret, such as single-page or mobile applications. |
Redirect URIs |
Required for the authorization code grant.
Up to 10 addresses of up to 2000 characters each, absolute, with a scheme and without a fragment ( |
Allowed scopes |
Shown under Authorization code; the scopes the application may ask for, see Scopes.
|
Back-channel logout URI |
Optional for any grant type; an https address that receives a message when the employee signs out, see Single Sign-On with OpenID Connect. |
Post-logout redirect URIs |
Optional, up to 10 addresses where the browser may be sent after the application asks for a sign-out. |
Roles |
Shown under Client credentials; the roles whose permissions the application acts with, see Client credentials. |
Name, description, roles, redirect URIs, allowed scopes and the logout addresses can be changed later with Edit. Grant types and the public or confidential choice stay as created.
The Client Secret
The dialog "OAuth application created" shows the client ID, the client secret and the address of the token endpoint.
The client ID never changes.
The client secret starts with csd_ocs_.
The dialog warns: "Copy the client secret now. It is shown only once and cannot be shown again. Treat it like a password."
Afterwards the table shows only its prefix.
A public client has no client secret.
Regenerate secret stops the current secret at once and shows a new one. Access tokens already issued stay valid until they expire. Delete stops every token of the application at once.
Regenerate secret is not offered for a public client.
Client Credentials
An application with the client credentials grant acts as a service account with the roles assigned to it in the Roles field. It holds none of the rights of the employee who registered it, and it keeps working when that employee leaves. A change to its roles applies at the next call.
An operation that needs an employee is refused to such an application with a 403. Reading the current user and creating a record that must have an employee as its author are examples.
To obtain a token, send POST /oauth/token:
-
The body is form-urlencoded. Parameters in the query string are refused.
-
grant_type=client_credentials. -
The application authenticates with HTTP Basic, or with
client_idandclient_secretin the body. -
A
scopeis ignored: the roles decide what the token may do. -
An optional
resourcenames the address the token is meant for, see the table in Authorization code with PKCE.
The answer holds access_token (starting with csd_oat_), token_type (Bearer) and expires_in in seconds.
The grant issues no refresh token.
The application asks for a new token when the old one expires.
Errors are invalid_client (401), unauthorized_client for an application that does not hold the grant, invalid_request and invalid_target.
When an answer carries Retry-After, the application waits for the period it gives before it asks again.
# 1. Get an access token with the client ID and secret of the application
curl -s https://deals.example.com/oauth/token \
-u 'app_42:csd_ocs_REPLACE_WITH_THE_CLIENT_SECRET' \
-d grant_type=client_credentials
The answer looks like this, with the token shortened:
{"access_token":"csd_oat_REPLACE","token_type":"Bearer","expires_in":7200}
# 2. Call the REST API with the token; the roles of the application decide what is returned
curl -s https://deals.example.com/api/clients/deals \
-H 'Authorization: Bearer csd_oat_REPLACE'
The second call returns the deals that the application’s roles allow it to read. An application whose roles grant nothing on deals receives 403. 7200 seconds is the default lifetime of 120 minutes, see Token lifetime.
Authorization Code with PKCE
The flow follows RFC 6749, section 4.1, with PKCE (RFC 7636). The employee signs in, including two-step verification when the account has it, and allows the application.
Step 1: authorization request
GET /oauth/authorize with these parameters:
| Parameter | Value |
|---|---|
|
|
|
The client ID of the application. |
|
One of the registered redirect URIs, character for character. |
|
The scopes, separated by spaces, at most 20. Send it explicitly: a registered application that sends none receives a token without scopes. |
|
Optional, up to 2048 characters. It comes back unchanged. |
|
Optional, up to 512 characters. It ends up in the ID token. |
|
The PKCE challenge and the method |
|
Optional. The address of a resource the server serves, for example |
|
Optional: |
An error found before the client and its redirect address are verified is shown on a page of CityScreen Deals and is never sent to the application.
Any other error returns the browser to the redirect address with error, state and iss.
Step 2: the browser returns with a code
After the employee allows the application, the browser returns to the redirect address with code, state and iss, the address of the issuer.
The code starts with csd_oac_, lives 5 minutes and works once.
Presenting a used code again revokes the tokens that were issued from it.
Step 3: exchange the code
POST /oauth/token, form-urlencoded, with:
-
grant_type=authorization_code; -
code; -
redirect_uri, the same address as in the authorization request; -
code_verifier, when the authorization request had a challenge; -
a confidential client authenticates with HTTP Basic or with
client_idandclient_secretin the body, and a public client sendsclient_idonly.
The answer holds access_token, token_type, expires_in and scope.
It also holds refresh_token (starting with csd_ort_) when the application has Issue refresh tokens, and id_token when the scopes include openid.
A code that is wrong, used, expired or issued to another client, a wrong verifier and a wrong redirect address all give the same invalid_grant (400).
A confidential client with a wrong secret gets invalid_client (401) instead.
When the answer carries Retry-After, the application waits for the period it gives before it tries again.
Step 4: refresh
POST /oauth/token with grant_type=refresh_token and refresh_token, authenticated as in step 3.
A scope in the request is ignored: the new tokens keep the scopes the employee allowed.
A public client receives a new refresh token with every refresh, and the old one stops working. Presenting an old refresh token again revokes the whole family of tokens. A confidential client keeps its refresh token and receives a new access token.
A refresh token has no expiry date. It stops when it is revoked, when the employee revokes the authorization, when the application is deleted or when the employee is deactivated.
# 1. The application creates a verifier and its S256 challenge
verifier=$(openssl rand -base64 48 | tr '+/' '-_' | tr -d '=\n')
challenge=$(printf '%s' "$verifier" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')
# 2. It opens this address in the employee's browser (line breaks added for reading)
# https://deals.example.com/oauth/authorize
# ?response_type=code
# &client_id=app_43
# &redirect_uri=https%3A%2F%2Ftools.example.com%2Fcallback
# &scope=api
# &state=af0ifjsldkj
# &code_challenge=<the value of $challenge>
# &code_challenge_method=S256
# 3. The browser comes back to
# https://tools.example.com/callback?code=csd_oac_REPLACE&state=af0ifjsldkj&iss=https%3A%2F%2Fdeals.example.com
# 4. The application exchanges the code; a public client sends no secret
curl -s https://deals.example.com/oauth/token \
-d grant_type=authorization_code \
-d code='csd_oac_REPLACE' \
--data-urlencode redirect_uri='https://tools.example.com/callback' \
-d code_verifier="$verifier" \
-d client_id=app_43
The answer looks like this, with the tokens shortened:
{"access_token":"csd_oat_REPLACE","token_type":"Bearer","expires_in":7200,"scope":"api","refresh_token":"csd_ort_REPLACE"}
# 5. Call the REST API with the employee's access rights
curl -s https://deals.example.com/api/clients/deals \
-H 'Authorization: Bearer csd_oat_REPLACE'
# 6. When the access token expires, refresh it
curl -s https://deals.example.com/oauth/token \
-d grant_type=refresh_token \
-d refresh_token='csd_ort_REPLACE' \
-d client_id=app_43
The call in step 5 returns the deals that the employee may read. The new answer in step 6 carries a new refresh token that replaces the old one.
Scopes
| Scope | What it allows |
|---|---|
|
Makes the request an OpenID Connect request. The answer carries an ID token, and the token opens the UserInfo endpoint. |
|
Adds |
|
Adds |
|
Adds |
|
Lets the token call the REST API with the employee’s access rights. |
A token issued for an employee without the scope api reaches only UserInfo.
The REST API answers it with 403, the challenge Bearer error="insufficient_scope", scope="api" and the message "The OAuth access token was issued without the api scope, which the CSD API requires. Authorize the application again and allow it to act in CSD."
A token can do only what the employee’s own permissions allow at each call, and its scopes limit it further.
Client credentials tokens take no scopes.
A request for any other scope, including offline_access, is refused.
The Consent Page
The employee signs in and presses Allow once.
With the scope api the application then calls the REST API with that employee’s own access rights, as they are at the time of each call.
The employee sees every application they allowed under Account > Authorizations, and withdraws the permission there with Revoke.
The sign-in form is titled "Sign in to {{instance}} to continue to {{application}}", with the names of your organization and the application filled in.
It runs the same steps as web sign-in, see Signing In and Out.
The consent page is titled "{{application}} asks for access" and lists what the application will be able to do and which details about the employee it will receive.
It offers Allow and Deny.
Deny sends access_denied to the application.
An application that registered itself carries the badge "Unverified" and a warning.
The page is skipped for an application the employee already allowed with the same scopes.
The parameter prompt changes that:
prompt |
Effect |
|---|---|
|
The page is shown again. |
|
The employee signs in again on the page. |
|
No page is shown.
The application receives a code if the employee is signed in and allowed it before, and otherwise |
Revoking in Account > Authorizations stops the application’s access and refresh tokens at once. The application can ask the employee again. An application with a back-channel logout address is told, see Single Sign-On with OpenID Connect.
Applications That Register Themselves
Some applications cannot be registered by an administrator in advance.
They register with POST /oauth/register, a JSON request following RFC 7591, and need no credential.
| Member | Rule |
|---|---|
|
Required, 1 to 10 addresses without fragment or user information, each with at most 2000 characters.
Each is an https address, an http address on a loopback host ( |
|
Optional; only |
|
Optional; the only accepted value is |
|
Optional, up to 255 characters. |
|
Optional, absolute http or https addresses. |
Logout members |
A self-registering application has no logout address, so a request that contains logout members is refused. |
The answer is 201 with a client_id of the form dcr_<22 characters> and token_endpoint_auth_method set to none.
There is no client secret, so the client is public and uses PKCE.
Without a scope in its authorization request the client receives api.
Errors are invalid_redirect_uri, invalid_client_metadata and 429 Too Many Requests.
A registration creates nothing in your organization. A registration that no employee allows expires. When an employee allows it, a record of the application is created and owned by that employee. The record is a public client with the authorization code and refresh token grants, every known scope allowed, no roles and no secret. Creating it needs the "OAuth applications" Create permission at Own scope, and it counts toward the license limit of OAuth applications. An employee without the permission sees "Your account is not allowed to connect applications. Ask an administrator of your organization." When the limit is reached the employee sees "The limit of connected applications of your organization has been reached. Ask an administrator of your organization."
Administrators see these records in the table and can delete them. Their settings cannot be changed: "This application registered itself, so its settings cannot be changed here. You can delete it." When an employee revokes such an application under Authorizations, the record is deleted with it, which needs the Delete permission at Own scope.
Revoking Tokens
POST /oauth/revoke with the form parameter token revokes an access token or a refresh token.
Revoking a refresh token also revokes its whole family: the access tokens issued from it and the refresh tokens that replaced it.
A client_id, when sent, must be the client the token was issued to, otherwise nothing is revoked.
The answer is an empty 200 for every token, including one that is unknown or already revoked, so the answer does not reveal which.
A request without a token gets 400 invalid_request.
Other ways to end tokens:
-
an employee revokes an authorization under Account > Authorizations;
-
an administrator deletes the application;
-
an employee is deactivated, which deletes every OAuth token issued for them.
Token Lifetime
An administrator sets "Access token lifetime for OAuth applications (minutes)" in Settings > General. The value is from 5 to 1440 minutes and defaults to 120. A change applies to tokens issued after saving. The ID token lives as long as the access token it is issued with.
Permissions
| Permission | Use |
|---|---|
"OAuth applications" View, Create, Edit and Delete at organization scope |
Administrators who register and manage applications. |
"OAuth applications" Create and Delete at Own scope |
Employees who connect applications that register themselves. |
"Rotate signing key" |
Administrators who rotate the signing key. |
Roles are edited in Roles & Permissions.
Related pages
-
Single Sign-On with OpenID Connect — using an application to sign employees in to a web application, and signing them out again
-
Access Tokens and App Passwords — tokens that an employee creates for scripts
-
Your Account — where employees see and revoke the applications they allowed
-
Password Policy and Sign-In Protection — sign-in protection
-
Roles & Permissions — the permissions for OAuth applications
-
Integrations — all connections to other systems