CORE API Tokens
- JSON Web Tokens (JWT): Tokens that conform to the JSON Web Token standard and contain information in the form of claims. These are self-contained which means it is not necessary for the issuer to call the server to validate the token.
- Opaque Tokens: Tokens in a proprietary format that typically contain some identifier information in a server’s persistent storage. To validate an opaque token, the recipient needs to call the server that issued the token.
CORE API primarily uses the following token-based authentication.
ID Token
An ID Token is a JWT (JSON web token), that is, a cryptographically signed Base64-encoded JSON object. The ID Token contains user profile attributes represented in the form of claims. These claims are statements about the user, which can be trusted if the consumer of the token can verify its signature. The ID Token is consumed by the application to get user information like the user's name, email, and so forth, typically used for UI display. You can get an ID Token for a user after they successfully authenticate. You must verify the ID Token's signature before storing and using it. You will need to decode this token to read the claims (or attributes) of the user. The JWT website provides a list of libraries you can use to decrypt the ID Token. It was added to the OIDC specification as an optimization so the application can know the identity of the user, without having to make an additional network request. The ID Token conforms to an industry standard and consists of three parts:
Header: Contains the type of token and hash algorithm used on the contents of the token.
- kid—the id of the key used to sign the payload
- alg—the hashing algorithm used, such as HMAC SHA256 or RSA
Body: Also called the payload, it contains the identity claims about a user. There are some claims with registered names for things like the issuer of the token, subject of the token (who the claims are about), and time of issuance. If ID Token is returned in URLs, care must be taken to keep the JWT within the browser size limitations for URLs.
Signature:
The header consists of two parts:
Example:
The second part of the token is the payload, which contains the claims. Claims are metadata about the user. CORE ID tokens include the following claims:
Claim | Description |
---|---|
aud | Audience. Either a single case-sensitive string or URI or an array of such values that uniquely identify the intended recipients of this JWT. For a CORE issued ID token, this will be the Client ID of your CORE application. This is a registered claim according to the JWT Specification |
auth_time | The time the ID token was authorized. |
exp | Expiration time. A number representing a specific date and time in the format “seconds since epoch” as defined by POSIX6. This claim sets the exact moment from which this JWT is considered invalid. This is a registered claim according to the JWT Specification |
iat | Issued at time. A number representing a specific date and time (in the same format as exp) at which this JWT was issued. This is a registered claim according to the JWT Specification |
iss | Issuer. A case-sensitive string or URI that uniquely identifies the party that issued the JWT. For a CORE issued ID token, this will be the URL of your CORE tenant |
sub | An identifier for the user, unique among all CORE accounts and never reused. A CORE account can have multiple emails at different points in time, but the sub value is never changed. Use sub within your application as the unique-identifier key for the user e.g., github|1234567890 |
Example:
The signature is used to verify that the sender of the JWT is who it says it is and to ensure that the message did not change along the way. To create the signature, sign a concatenation of the encoded header, the encoded payload, and a secret with the specified algorithm. For example, if you use the HMAC SHA256 algorithm, the signature is created in the following way:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
How to Get an ID Token?
The ID Token can be returned while authenticating the CORE API user. This includes a call to the authentication API. To retrieve an ID token, the response type should consist of ID token, both for client-side and server-side authentication flows. To know more click here.
Validate an ID Token
Typically, it is critical that you validate an ID token before you use it, but as you are communicating directly with CORE over an intermediary-free HTTPS channel and using your client secret to authenticate yourself to CORE, rest assured that the token you receive comes from CORE and is valid. However, as a best practice, we recommend validating the ID.
Since most API libraries combine the validation with the work of decoding Base64 and parsing JSON, you probably end up validating the token anyway as you access the fields in the ID token. To validate an ID Token, an application needs to verify the signature as well as validate the standard claims of the token. Each of these steps is discussed in more detail below.
Most JWT libraries will take care of the token validation for you automatically, so be sure to reference the Libraries for Token Signing/Verification section of JWT.io to find a JWT library for your platform and programming language.
To validate the ID Token, verify the following:
Verify the Signature
The signature is used to verify the sender of the token and to ensure that the message does not change along the way. Remember that the ID Token is always a JWT and the signature is created using its header and payload, secret and hashing algorithm being used (as specified in the header: HMAC, SHA256or RSA). The way to verify it depends on the hashing algorithm.
- For HS256, the APIs Signing Secret is used. You can find this information in your APIs Settings.
Note that the field is only displayed for APIs that use HS256.
- For RS256, the tenant's JSON Web Key Set (JWKS) is used. Your tenant's JWKS is
/.well-known/openid-configuration/jwks
The most secure practice, and our recommendation, is to use RS256.
Verify the Claims
After the application verifies the token's signature, the next step is to validate the standard claims of the token's payload. The following validations need to be made:
- Token expiration: The current date/time must be before the expiration date/time listed in the exp claim (which is a UNIX timestamp).
- Token issuer: The issuer claim denotes the issuer of the JWT. The value must match the URL of your CORE API tenant. For JWTs issued by CORE API, iss holds your CORE API domain with a https://prefix and a / suffix: https://bqecore.com/.
- Token audience: The aud claim identifies the recipients that the JWT is intended for. The value must match the Client ID of your CORE API application.
How to Control the Contents of an ID Token?
The attributes included in the issued ID Token are controlled by the use of a parameter called scope.
- If the scope is set to openid, then the ID Token will contain only the iss, sub, aud, exp and iat claims.
- If the scope is set to openid email, then the ID Token will contain additionally the email and email_verified claims.
- If the scope is set to openid profile, then the ID Token will contain all default profile claims, which are: name, family_name, given_name, middle_name, nickname, preferred_username, profile, picture, website, gender, birthdate, zoneinfo, locale, and updated_at.
The exact claims contained in the ID Token will depend on the scope parameter you sent to the /authorize endpoint. A CORE API ID Token will always include the registered claims and subclaim, but the others depend on the scope.
Token Lifetime
The purpose of the ID Token is to cache user information for better performance and experience, and by default, the token is valid for 3600 seconds or one hour. Remember that the ID Token helps ensure optimal performance by reducing the need to contact the Identity Provider every time the user performs an action that requires an API call.
There are cases where you might want to renew your ID Token. To do so, you can either perform another authorization flow with CORE API (using the /authorize endpoint) or use a Refresh Token. When performing the initial authorization flow, you can ask for a Refresh Token by adding offline_access to the scope parameter, for example, scope=openid offline_access.
The Refresh Token is stored in a session, along with the ID Token. Then, when a session needs to be refreshed (for example, a preconfigured timeframe has passed or the user tries to perform a sensitive operation), the app uses the Refresh Token in the background to obtain a new ID Token, using: /connect/token endpoint with grant_type=refresh_token.
This method is not an option for Single Page Apps (SPAs) because, for security reasons, you cannot get a Refresh Token from the Implicit Grant (the OAuth flow typically used from Client-side Web Apps). In that case, you have to use silent authentication. If you are using a SPA, then you can fetch a new token using the checkSession()method.
Obtaining User Information
In addition to the information in the ID token, you can get additional user profile information from CORE’s user profile endpoint. Retrieve the base URI using the key, userinfo_endpoint. The discussion here assumes the base URI is:
GET /connect/userinfo
The request might look like the following:
The response depends on scopes requested during the initial access token request. Here is a sample where scopes specified are openid, email, and profile:
Here is a sample response with all scopes—openid, profile, email, phone, address—
After obtaining user information, query your app's user database. If the user already exists in your database, initiate an application session for that user.
If the user does not exist in your user database, redirect the user to your new-user, sign-up flow. You may be able to auto-register the user based on the information you receive from CORE, or at the very least, you may be able to pre-populate many of the fields that you require on your registration form.
Revoke Access
Once issued, tokens cannot be revoked in the same fashion as cookies with session IDs for server-side sessions. As a result, tokens should be granted for relatively short periods and then renewed periodically, if the user remains active.
Access Token
Access Tokens are credentials used to access protected resources. An Access Token is a string representing an authorization issued to the client. The string is usually opaque to the client. Tokens represent specific scopes and durations of access, granted by the resource owner, and enforced by the resource server as well as the authorization server. The token may denote an identifier used to retrieve the authorization information or may self-contain the authorization information in a verifiable manner (i.e., a token string consisting of some data and a signature). CORE API uses Access Tokens to protect access to the CORE API resources.
Overview
It can be any token (such as an opaque string or a JWT) meant for CORE APIs. Its purpose is to inform the API that the bearer of this token has been authorized to access the API and perform specific actions (as specified by the scope that is granted). The Access Token should be used as a bearer credential and transmitted in an HTTP Authorization header to the API.
Access Token Format
CORE APIs generate Access Tokens in two formats:
- opaque strings
- JSON Web Tokens (JWT)
It depends on the value that the audience parameter has in the authorization request. If the audience, is set to YOUR_CORE_DOMAIN/userinfo, then the Access Token will be a JSON Web Token (JWT). If the audience, set to a custom API and the scope parameter includes the openid value, then the generated Access Token will be a JWT valid for both retrieving the user's profile and for accessing the custom API. The aud claim of this JWT will include two values: YOUR_CORE_DOMAIN/userinfo and your custom API's unique identifier.
Using an Access Token
Access Tokens are to access user-owned resources. For example, an Access Token requires access to a CORE activity API. Such access, requested by the application and granted by the user using the authorize endpoint.
In this case, the user will be prompted to permit access to activity (scope=readwrite: core). If allowed, an Access Token issued to the application, which the application can then use when making requests to the activity API. If the user has already granted consent, no consent dialog will be displayed, and the Access Token is issued without additional prompts. Also, the consent dialog might be shown again, if the access level changes. For example, if the user has granted read:core access, but the functionality changes and so readwrite:core access is required as well; the user will have to use the consent dialog to grant additional access.
Lifetime
Access tokens are valid for 3600 seconds (one hour), after which you need to get a fresh one. Once expired, an Access Token can no longer be used to access an API.
To regain access, obtain a new Access Token. This can be done by repeating the OAuth flow used to obtain the initial Access Token.
In some situations, it is desirable to have permanent, ongoing access to an API without having to repeat an OAuth flow. It is referred to as offline_access
and is possible with the use of Refresh Token. OAuth 2.0 endpoints issue a Refresh Token along with the Access Token. When the Access Token expires, the Refresh Token can be used to obtain a new Access Token with the same permissions, without further involvement from a user.
If your app uses an expired, revoked, or otherwise invalid Refresh Token, it gets the following response:
When the token expires, you will need to make a request for new tokens. If the request is successful, you will receive a new Access Token and a new Refresh Token.
Refreshing Access Token
Making the requestRetrieve the base URI for the request using the key, token_endpoint. The discussion here assumes the base URI is:
POST /connect/token
This endpoint is accessible over https; plain http connections are refused.
Field | Description |
---|---|
grant_type | Required. When requesting a refresh token, set this to refresh_token |
refresh_token | Required. The refresh token returned in the last access token response MUST be used. All other refresh tokens are stale and unusable |
client_id | Required. This is your application's Client ID |
client_secret | Required. This is your application's Client Secret (only required for confidential applications) |
The actual request might look like the following:
Handling the response
A successful response to this request contains the following fields:
Field | Description |
---|---|
access_token | The token that must be used to access the CORE APIs. The previous token is invalidated. |
expires_in | The remaining lifetime of the access token in seconds. The value always returned is 3600 seconds (one hour). Use the refresh token to get a fresh one. |
refresh_token | A token used to obtain a new access token. All previous refresh tokens are stale and unusable. |
token_type | Identifies the type of token returned. At this time, this field will always have the value Bearer. |
refresh_token expires_in | The remaining lifetime, in seconds, for the connection, after which time the user must re-grant access. |
Revoke Access Token
Your app can programmatically revoke access given to it by a specific user when they click the disconnect link in your app. Use the revoke endpoint to request permissions granted to the application to be removed.
As a best practice, monitor and revoke connections to your app for users that are no longer valid customers. This helps you, the developer, and the CORE group to know true conversion and retention rates for your app.
Retrieve the base URI for the revoke endpoint using the key, token_endpoint. The discussion here assumes the base URI is:
POST /connect/revocation
The request might look like the following:
This request returns an empty response body and one of the following status codes:
Code | Description |
---|---|
200 | Successful revoke. |
400 | One or more of BearerToken, RefreshToken, ClientId or,ClientSecret are incorrect. |
401 | Bad authorization header or no authorization header sent. |
500 | CORE server internal error, not the fault of the developer. |
Refresh Token
Refresh tokens are credentials used to obtain new Access Tokens. Refresh Tokens are issued to the client by the Authorization Server when the current access token becomes invalid or expires. A Refresh Token is a string representing the authorization granted to the client by the resource owner. The string is usually opaque to the client. The token denotes an identifier used to retrieve the authorization information. Unlike Access Tokens, Refresh Tokens are intended for use only with authorization servers and not with resource servers. Refresh Tokens are subject to strict storage requirements to ensure that they are not leaked. Also, Refresh Tokens can be revoked by the Authorization Server.
Overview
A Refresh Token allows applications to request the CORE APIs to issue a new Access Token directly, without having to re-authenticate the user. It will work as long as the Refresh Token has not been revoked or expired.
Restrictions
You can only get a Refresh Token if you are implementing: Authorization Code Flow. Because regular web apps are server-side apps where the source code is not publicly exposed, they can use the Authorization Code Flow, which exchanges an Authorization Code for a token.
A Single Page Application (usually implementing Implicit Grant) should not under any circumstances get a Refresh Token.
The reason for that is the sensitivity of this piece of information. You can think of it as user credentials because a Refresh Token allows a user to remain authenticated essentially forever. Therefore, you cannot have this information in a browser; it must be stored securely.
How to Get a Refresh Token?
To get a Refresh Token, you must include the offline_access scope when you initiate an authentication request through the authorize endpoint.
For example, if you are using Authorization Code Grant, the authentication request would look like the following:
After the user authenticates successfully, the application will be redirected to the redirect_uri, with a code as part of the URL:
/callback?code=BPPLN3Z4qCTvSNOy
You can exchange this code with the: /connect/token endpoint.
The response should contain an Access Token and a Refresh Token.
Refresh Tokens must be stored securely by an application.
Using Refresh Token
To refresh your token, use the Refresh Token you already got during authorization and make a POST request to the : /authorize/token endpoint in the Authentication API, using grant_type: refresh_token.
where:
Parameters | Description |
---|---|
grant_type | This is the type of grant to execute |
client_id | This is your application's Client ID |
client_secret | (optional) This is your application's Client Secret (only required for confidential applications) |
refresh_token | This is the Refresh Token to use |
The response will include a new Access Token, its type, its lifetime (in seconds), and granted scopes. If the scope of the initial token included openid, then a new ID Token will be in the response as well.
Reauthorizing the Connection
Access to the CORE company terminates when the current refresh_token expires. If your app uses an expired, revoked, or otherwise invalid refresh_token, it will get the following response:
{
"error": "invalid_grant"
}
At this point, the connection is disabled and access to your app terminated. Your app must ask the user to reauthorize the connection.
Revoke Refresh Token
It is essential to be able to revoke Refresh Tokens in case they are compromised. CORE API handles token revocation as though the token has been potentially exposed to malicious adversaries. So each revocation request invalidates not only the specific token but all other tokens based on the same authorization grant. It means that all Refresh Tokens issued for the same user, application, and the audience will be revoked.
You can revoke a Refresh Token by posting a request to the Authentication API.
To revoke a Refresh Token, send a POST request to /connect/revocation
The API first validates the application credentials and then verifies whether the token was issued to the application making the revocation request. If this validation fails, the request is refused and the application is informed of the error. Next, the API invalidates the token. The invalidation takes place immediately and the token cannot be used again after the revocation.
Each revocation request invalidates all the tokens issued for the same authorization grant.
where:
Parameters | Description |
---|---|
client_id (Required) | Your application's Client ID. The application should match the one the Refresh Token was issued for |
client_secret (Required) | Your application's Client Secret. This is required for confidential applications |
token (Required) | This is the Refresh Token you want to revoke, it should match the application it was issued for |
If the request is valid, the Refresh Token is revoked and the response is HTTP 200, with an empty response body. Otherwise, the response body contains the error code and description.
Possible responses
Error Code | Description |
---|---|
200 | The Refresh Token is revoked, does not exist, or was not issued to the application making the revocation request. The response body is empty |
400 | The required parameters were not sent in the request ("error": "invalid_request") |
401 | The request is not authorized ("error": "invalid_client"). Check that the application credentials (client_id and client_secret) are present in the request and hold valid values |
500 | Internal server error |
Token Storage Best Practices
In persistent storage, save the OAuth Refresh Token and Client ID, associating them with the user who is currently authorizing access. Be sure to encrypt the Refresh Token before saving it to persistent storage. Then, decrypt it and store it in volatile memory when you need to use it to refresh the Access Token. The Access Token is supplied in the authorization header for every call to the CORE API resource. Store it in volatile memory, so it is readily available during contexts in which calls to API resources are made.
Examples of these contexts include:
- The life of a signed-in user session.
- The life of a connection.