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:

  1. User interactively performs logon against Authentication Server at the Authorization endpoint, resulting Authorization Code upon successful logon
  2. 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:

MethodMethod nameDescription
SHA-256S256SHA-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 textplainCode 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 parameterExplanationIs mandatory?
response_typeMust be set to: codeYes
client_idApplication ID you have obtained for your registered client application.Yes
redirect_uriURI 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_challengeMust be set to code challenge generated in previous phase. Yes
code_challenge_methodMust be set to method name used for generating code challenge.

Please note Applixure DOES NOT recommend using method plain in any circumstances.
Yes
scopeRequested 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.
stateOpaque 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:

ParameterExplanationIs mandatory?
grant_typeMust be set to: authorization_codeYes
codeAuthorization code that you received from the callback.Yes
redirect_uriOriginal redirect_uri value used in the first phase when performing authentication.Yes
code_verifierOriginal 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:

PropertyData typeExplanation
access_tokenstringAccess token.

This is a token to use subsequently for authorizing requests to Applixure APIs.
expires_inintegerValidity 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_tokenstringRefresh 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.
scopestringA 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_typestringAAS 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 CodeCondition
400 - Bad RequestNormal 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 ErrorTemporary error - retry after a while is recommended.

If condition persist, please be in contact with Applixure support for further assistance.
503 - Service UnavailableAAS is temporarily offline - retry after short while is recommended.