Authorization Code Grant with PKCE
Overview
Authorization Code Grant with Proof Key for Code Exchange is meant for obtaining access token using two-step process of:
- User interactively performs logon against Authentication Server at the Authorization endpoint, resulting Authorization Code upon successful logon
- Exchanging Authorization Code using Token endpoint into valid access token
This grant flow must be used for non-confidential clients that cannot store Client secret for your application registration, such as publicly distributed mobile clients etc., that need to access Applixure APIs using user account credentials. Regular Authorization Code Grant can be used for code that runs on trusted devices capable of storing Client secret for your application registration.
This flow uses an extension to base OAuth2 protocol to try and mitigate possible authorization code interception that would otherwise happen if client secret is not used.
Flow description
Code verifier generation
Code verifier
As a first phase, your application code - before calling any endpoints - has to generate a cryptographically random code verifier string that is between 43 and 128 characters in length, and can only contain following characters (i.e. characters allowed in URL variant of Base64 without padding):
- A-Z
- a-z
- 0-9
- "-", ".", "_" or "~"
Always use unique verifier
Code verifier should never be re-used across authentication attempts, always generate new code verifier for each new authentication attempt when using Authorization Code Grant!
Code Challenge
Based on the generated code verifier, application then has to derive a code challenge string from the verifier. This challenge string can be generated using either of two methods:
Method | Method name | Description |
---|---|---|
SHA-256 | S256 | SHA-256 hash function is applied against code verifier and resulting hash value encoded as URL safe variant of Base-64 string without padding (i.e. trailing = characters) is used as code challenge string. If application is technically capable of hashing using SHA-256, it MUST use this method |
Plain text | plain | Code challenge string is identical to code verifier string. |
An example of S256 code challenge
GIven cryptographically generated code verifier of "xHh9ioRsgVFv3O4Rgwdi.7IJ2KTKOtNfkUechMNAhHOfN35Iwo", treating each character as its ASCII representation ("0x78,0x48,0x68...") and hashing the whole string with SHA-256, resulting Base64Url encoded - without padding - code challenge would be: "WNGSeD2uXAfb4Ga_6b2J1Aj3XUl_D1FDVaBRFVaZ_qM".
Authentication with browser
Next, authentication step requires opening up Internet browser for the user and navigating into Authorization endpoint URL with the following parameters in the URI:
URI parameter | Explanation | Is mandatory? |
---|---|---|
response_type | Must be set to: code | Yes |
client_id | Application ID you have obtained for your registered client application. | Yes |
redirect_uri | URI that AAS uses to redirect browser in order to return result of the authentication and authorization operation to the caller. This value must match to one of the pre-defined redirect URIs for client application - Authorization Server never calls any other URIs. Must use HTTPS protocol or application specific protocol, except for localhost URIs for which HTTP is accepted. | Yes |
code_challenge | Must be set to code challenge generated in previous phase. | Yes |
code_challenge_method | Must be set to method name used for generating code challenge. Please note Applixure DOES NOT recommend using method plain in any circumstances. | Yes |
scope | Requested scopes (depending on API being used). | Yes, if no default scopes are defined for client application registration. No, if default scopes are defined for client application registration - in that case pre-defined scopes will be used for request. |
state | Opaque value used by the caller to maintain state/association between the call and getting the redirected response, that echoes this value as-is back. | No, but strongly recommended to prevent cross-site request forgery. |
An example of authorization endpoint URL
https://auth.applixure.com/oauth2/authorize?response_type=code&client_id=plbDrF3shSTQooL&code_challenge=WNGSeD2uXAfb4Ga_6b2J1Aj3XUl_D1FDVaBRFVaZ_qM&code_challenge_method=S256&scope=openid&redirect_uri=http%3A%2F%2Flocalhost%3A54833%2Fcallback&state=7dee7d5780a94ee3bbff31e84f5abda8
User will then see the Applixure logon screen and has to enter valid user account credentials, optionally verify logon with with 2FA token and finally consent into allowing the client application to obtain requested permissions as defined by the scopes.
Consent on first use
Once user has consented for specific scopes for specific registered client application, AAS will no longer ask about consent for the same application and for the same scopes for that user account.
Depending on the result of authentication and authorization operation, AAS will finally call back (i.e. redirect the browser) into specified callback URI that the client application should listen to to continue forward with the flow.
As AAS will redirect using GET HTTP method, both success and error result is signalled through URI parameters for the callback URI and no request body is used for the purpose.
If authentication attempt resulted an error response, do not proceed to next phase but handle the error condition and/or notify the user appropriately.
An example of authorization code callback URL
http://localhost:54833/callback?code=FtWXmTKps72U4iBaj5YW2w6q7XGWhwCcBnkfEUtDJHRdBFHYm9VtMsfZTGMStDddFKSSkzTXMuv3oqjEjapFFJvmiSDBLzRL3FW9R6BqisntP2kq9T7GC2NYG9FTnKQMkmqkaU4etUQdKJmmw1TPYhmzjM9biGxwXaVJrTPjFWs&state=7dee7d5780a94ee3bbff31e84f5abda8
Remember to check state!
If and when using state parameter, make sure to verify that your callback URI receives the same state parameter value back you originally generated for the request. If not, you should discard the response!
Getting access token
Next, using the authorization code received from the Authentication Server, you must exchange this code into valid access token using another endpoint.
For token exchange, you will need to send application/x-www-form-urlencoded
encoded HTTP request in UTF-8 character set to the token endpoint with following parameters:
Parameter | Explanation | Is mandatory? |
---|---|---|
grant_type | Must be set to: authorization_code | Yes |
code | Authorization code that you received from the callback. | Yes |
redirect_uri | Original redirect_uri value used in the first phase when performing authentication. | Yes |
code_verifier | Original code verifier string that application created in first phase and from which the code challenge was calculated for authentication phase. | Yes |
An example of token endpoint payload
grant_type=authorization_code&code=FtWXmTKps72U4iBaj5YW2w6q7XGWhwCcBnkfEUtDJHRdBFHYm9VtMsfZTGMStDddFKSSkzTXMuv3oqjEjapFFJvmiSDBLzRL3FW9R6BqisntP2kq9T7GC2NYG9FTnKQMkmqkaU4etUQdKJmmw1TPYhmzjM9biGxwXaVJrTPjFWs&redirect_uri=http%3A%2F%2Flocalhost%3A54833%2callback&code_verifier=xHh9ioRsgVFv3O4Rgwdi.7IJ2KTKOtNfkUechMNAhHOfN35Iwo
As Authorization Code Grant flow with PKCE is intended for untrusted clients that cannot store Client secret, calling token endpoint in this flow does not require client authentication.
Successful call result
If token endpoint call is successful, you will receive JSON formatted payload back with following properties available:
Property | Data type | Explanation |
---|---|---|
access_token | string | Access token. This is a token to use subsequently for authorizing requests to Applixure APIs. |
expires_in | integer | Validity time of the access token in seconds from the time of issuance. Always set to 3600 i.e. 1 hour. Caller is responsible for tracking lifetime of access tokens it has received for longer time usage and if necessary, refresh it using refresh_token (if present). |
refresh_token | string | Refresh token (if issued). This is a token to use to obtain a new access token when the lifetime validity of access token expires (see: expires_in). Refresh tokens are valid for 90 days from issuance. |
scope | string | A space-delimited list of scopes that has been granted for access token. Please note that depending on the privileges and permissions of the user account that was used to authenticate in phase 1 of the flow, granted scopes may be a subset of the scopes originally requested! |
token_type | string | AAS always returns tokens of type bearer |
An example of success JSON payload
{ "access_token": "2bCL1o2gTwFrsMaSFBK1FbusqfdDUR5J7WyDcci8BkxY4zzQZ7S...", "token_type": "bearer", "expires_in": 3600, "refresh_token": "AXXtUZBWvfee7KSiSL98RwhYtNwEMhaswN7LkySYPXoUneYmi8mny4AzmtpRvs6dcK...", "scope": "environments:read users:manage" }
Error call result
Possible HTTP error response codes returned are:
HTTP Error Code | Condition |
---|---|
400 - Bad Request | Normal error condition when request could not be processed by the token endpoint as per RFC 6749 Section 5.2. Please inspect returned JSON response body for a reason for call failure. |
500 - Internal Server Error | Temporary error - retry after a while is recommended. If condition persist, please be in contact with Applixure support for further assistance. |
503 - Service Unavailable | AAS is temporarily offline - retry after short while is recommended. |
Updated over 1 year ago