Leveraging Proof Key for Code Exchange (PKCE) in the Authorization Code Grant Flow
To mitigate against the threat of authorization code interception attacks, the ActivID AS server supports Proof Key for Code Exchange (PKCE). For public clients, it is required to use PKCE.
For further information about PKCE, see the OAuth 2.0 PKCE specification.
PKCE Usage in Authorization Code Flow
-
The client dynamically creates a unique ‘Code Verifier’ (a cryptographic random key) for the authorization request using the following format:
code-verifier = 43*128unreserved
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
ALPHA = %x41-5A / %x61-7A
DIGIT = %x30-39
The code verifier is then generated by encoding the 43-octet sequence in Base64URL.
-
The client creates the ‘Code Challenge’ by transforming the value of the unique code verifier for the authorization request using one of the following code_challenge_method options:
-
plain:
code_challenge = code_verifier
-
S256:
code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
-
-
The client sends the Code Challenge with the Authorization Request to the authorization server to obtain the authorization code.
For example:
CopyURL invoked with the code_challenge_method as plain
https://server.example.com:8445/idp/domain/authn/login?client_id=spl-api&response_type=code&scope=openid+profile&redirect_uri=https://localhost:8080&code_challenge_method=plain&code_challenge=NDdERVFwajhIQlNhLV9USW1XLTVKQ2V1UWVSa201Tk1wSldaRzNoU3VGVQ
CopyURL invoked with the code_challenge_method as S256
https://server.example.com:8445/idp/domain/authn/login?response_type=code&client_id=OpenID_admin&redirect_uri=http://localhost&scope=openid&code_challenge_method=S256&code_challenge=45ee543e8b243eef8cc086a695c14b73ba0edc2d1bedaeb6549b5dde6f6a2d49
Note: The code_challenge_method is optional. If it is not present, the default value is plain.
-
The server redirects the response to the predefined redirect_uri with a valid code.
For example:
Copyhttp://server.example.com:8445/redirect/?code=35256753&context=PARAMETER_AUTHENTICATION_TYPE_CODE%3AAT_EMPPWD%3Afalse+LEVEL_OF_ASSURANCE%3A2%3Afalse+
-
The client (that requested the authorization code) sends the obtained Authorization Code and the Code Verifier to the token endpoint as the Access Token Request.
The request also includes the client authentication (such as client_secret_basic. or the bearer access token) for a confidential client. For the public client, the client authentication is not sent.
- For confidential clients:
- PKCE is not required, but it is supported
- Client authentication should be sent (client basic, bearer token etc.)
- For public clients:
- PKCE is required
- No client credential is sent
- code_verifier is required
CopySample request (with a confidential client)
POSThttps://[base-server-url]/{tenant}/authn/token HTTP/1.1
Accept-Encoding:gzip,deflate
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer Z+KhiAAAAWNzjH1N2CIYsVDj3QN4Q+QBlDfS1c/h
grant_type=authorization_code&code=35256753&redirect_uri=http%3A%2F%2Flocalhost&client_id=OpenID_admin&code_verifier=NDdERVFwajhIQlNhLV9USW1XLTVKQ2V1UWVSa201Tk1wSldaRzNoU3VGVQCopySample request (with a public client)
POSThttps://[base-server-url]/{tenant}/authn/token HTTP/1.1
Content-Type:application/x-www-form-urlencoded
grant_type=authorization_code&code=17312836&redirect_uri=http%3A%2F%2Flocalhost&client_id=OpenID_admin&code_verifier=NDdERVFwajhIQlNhLV9USW1XLTVKQ2V1UWVSa201Tk1wSldaRzNoU3VGVQIf the code_verifier is not present, an error will be returned.
- For confidential clients:
-
The code verification is performed during Access Token retrieval. The server compares the Code Verifier (based on the code_challenge_method) with the previously received request code (proof of possession of the "code verifier" by the client) before returning the tokens:
-
If the method was S256, the Code Verifier is hashed and encoded, and then compared to the Code Challenge:
BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) == code_challenge
-
If the method was plain, the Verifier and Challenge codes are compared directly:
code_verifier == code_challenge
If the verification is successful, the server returns the access token. Otherwise, it returns errors.
-
Sample Error Responses
Client does not support public clients
HTTP/1.1 400 Bad Request
Cache-Control: no-store
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
{
"error_description":"Unauthorized client",
"error":"unauthorized_client"
}
The request does not contain a code_verifier
HTTP/1.1 403 Forbidden
Cache-Control: no-store
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
{
"error_description":"Access denied by resource owner or authorization server:Code verifier missing",
"error":"access_denied"
}
The code is invalid, or the client_id, direct_uri do not match
HTTP/1.1 400 Bad Request
Cache-Control: no-store
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
{
"error_description":"Invalid grant",
"error":"invalid_grant"
}