Overview
In the first part, we have shown how the OAuth 2.0 Authorization code grant works when using Keycloak and Postman. Authorization code flow is the most common secure OAuth 2.0 flow. In the sixth step of that process, the client should provide client credentials in a base64 encoding format for requesting an access token. Unfortunately, for public clients like a mobile app or a single-page app, keeping client credentials secrets safe is impossible. There is no way for public clients to guarantee the security of the client credentials, which is used for requesting an access token. In addition, for the mobile app there is another threat. Malicious applications on the user's device can capture the redirect URL to receive an authorization code from the authorization server to then exchange for their own access token.
Requirement
For the following steps in this blog post on your local machine, you need to have the Keycloak server running, a Keycloak realm, and at least one user created. You also need to have the Postman on your local machine.
Securing code exchange with PKCE
Given the above issues, OAuth 2.0 provides a more secure authorization flow to a better secure mobile apps or other types of public clients.
From the RFC 7636: Proof Key for Code Exchange:
ℹ️ PKCE (RFC 7636) is an extension to the Authorization Code flow to prevent CSRF and authorization code injection attacks. PKCE is not a replacement for a client secret, and PKCE is recommended even if a client is using a client secret.
The way PKCE, pronounced “pixy”, works is quite simple. Before the client redirects the user to the authorization server endpoint for initializing a new authorization code flow, it generates another random value, known as the code verifier
. The client also stores this new random value locally. Rather than sending this value directly to the authorization server, the client first should compute the hash value of the code verifier
to create a code challenge
using the SHA-256 hash function. Then the client adds the code challenge
as part of the authorization request using the following additional parameters:
code_challenge
REQUIRED.
Code challenge.
code_challenge_method
OPTIONAL.
Defaults to "plain" if not present in the request.
Code verifier transformation method is "S256" or "plain".
Later, when the client calls the authorization server token endpoint to exchange the authorization code for an access token, it sends the original code verifier
(unhashed) in the request. The authorization server will check that the SHA-256 hash of the code verifier
matches the code challenge that is received in the authorization request.
If an attacker intercepts both the redirect to the authorization server and the response authorization code, it cannot use the authorization code because it can not compute the correct code verifier
.
Authorization code flow with PKCE
Step 1
For the first step, we need to fill all needed OAuth 2.0 configuration options, then click on Get New Access Token in the Postman Authorization tab.
- Auth URL:
{server}/auth/realms/{realm}/protocol/openid-connect/auth
- Access Token URL:
{server}/auth/realms/{realm}/protocol/openid-connect/token
Step 2
Postman redirects the user with its embedded browser to the Keycloak’s auth endpoint. Postman includes Client Id (client_id
) and required scopes (scope
) in this redirect. Also, Postman generates a new random value for the code verifier
and adds the hash value of it to the redirect URL as a new query parameter.
HTTP 200
GET https://KEYCLOAKDOMAIN/auth/realms/test-realm/protocol/openid-connect/auth?
response_type=code&
client_id=CLIENTID&
state=state_value&
scope=offline_access&
redirect_uri=https://localhost:8081/test-callback&
code_challenge=Q0J7-pF3nmAP3XrTmUt6DEFL9vKG9_1V12fXXMTVIqk&
code_challenge_method=S256
Step 3
Same as for standard authorization code flow, Keycloak loads an HTML form and authenticates the user, and asks for consent to grant access to the client (Postman).
Step 4
The User authenticates the request by filling out and submitting the form.
Step 5
If Keycloak approves the User, then Keycloak redirects the web browser to a URI (redirect_uri
) controlled by the Client (Postman), including an authorization code (code
) and the original state value as query parameters. Keycloak also stores the code challenge
and code challenge method
alongside the state parameter.
HTTP 302
Response Header:
Location: https://localhost:8081/test-callback?
state=state_value&
code=cc45ea5d-a930-4950-a2c2-62a9f29acfbf.7ecefe6d-021d-4a3b-9a26-e780a6680ecf.7306139f-c07c-4adc-b175-f6c509b80964
Step 6
Now, Postman calls the authorization server (Keycloak) token endpoint to exchange the authorization code for an access token to access the Resource Server API on the user’s behalf. It sends the authorization code and code verifier in the body of a POST request, using application/X-WWW-form-urlencoded
encoding with the following parameters and authorization header, which supply the client credentials (client_id:client_secret
) in a base64 encoding format:
HTTP 200
POST https://KEYCLOAKDOMAIN/auth/realms/test-realm/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic dGVzdC1jbGllbnQ6aUxUTGFJelNuM3pUdVAyZHhMY2FJc3JiVldNQXZkNzg=
Body:
grant_type: "authorization_code"
code: "cc45ea5d-a930-4950-a2c2-62a9f29acfbf.7ecefe6d-021d-4a3b-9a26-e780a6680ecf.7306139f-c07c-4adc-b175-f6c509b80964"
redirect_uri: "https://localhost:8081/test-callback"
code_verifier: "tClcOwZdqiPHHuMo0CyxMked9r1NJ_5_BicA0FI1Q0E"
client_id: "CLIENTID"
Step 7
If the authorization code is valid and has not expired, then Keycloak will respond with the access token in an application/json
encoded body along with some optional details about the scope and expiry time of token.
HTTP 200
Content-Type: application/json
Body:
access_token: "eyJh...",
expires_in: 300,
refresh_expires_in: 0,
refresh_token: "eyJh...",
token_type: "Bearer",
not-before-policy: 0,
session_state: "60a62786-1bf3-4a78-b4e2-89d414ee2026",
scope: "offline_access email profile"
Step 8
Once the Postman has obtained an access token, it can use it to access the Resource Server API by including it in the header of HTTP requests as Authorization: Bearer eyJh...
.
Wrap-up
In this blog post, we showed what the problem might be when we use Authorization code grant type, how OAuth 2.0 Authorization code grant with PKCE works and how Postman can do that for us.
Top comments (0)