Thursday, October 6, 2022

OAuth 2.0: Authorization Code with PKCE

In this post, let's have a look at Authorization Code with PKCE (Short for Proof Key for Code Exchange, pronounced: pixy) Flow in OAuth 2.0.

In a previous post (OAuth 2.0: Authorization Code Vs Implicit Flow), I wrote about Authorization Code flow in OAuth 2.0, I'd highly suggest reading that post first before this, as I am not going to explain Authorization Code flow here in this post.

Authorization Code Flow
In the Authorization Code flow, in order to exchange authorization code to an access_token, when the Client makes to call to /token endpoint, the client needs to send the client_secret and that introduces a security risk because it has to be stored somewhere.

With the Authorization Code with PKCE, before starting the Authorization Code Flow, the Client generates a random value called code_verifier. The client then hashes this code_verifier and the result is called the code_challenge. Now the authorization code flow starts the same way, except /authorize request includes code_challenge in the query string.

GET: https://login.microsoftonline.com/<tenant>/oauth2/v2.0/authorize?
&client_id=myapplication-client
&response_type=code
&redirect_uri=https://myapplication.com/callback
&scope=Calendars.Read
&state=some-state
&code_challenge=fwfLrb--atJiWz5SBUa1-OkzAQIP1w6uuDAA2fAp-Yg

The Authorization Server stores the code_challenge for later verification and after the user authenticates, redirects back to the client with an authorization code, just like in the Authorization Code flow. Now when the client makes the request to exchange the authorization code for an access_token, it sends the code_verifier instead of the client_secret.

POST: https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token
content type application/x-www-form-urlencoded
 
grant_type=authorization_code
client_id=myapplication-client
code=<code_received_from_authorize_endpoint>
code_verifier=y5jMOEF7Nk2sHLZcdZ-eR19hLd4xZL32f-79qljcJNotYRD_FQGzF5v5ouMpABFkvp0zH7JNxHe57JpV

Now the Authorization Server hashes the code_verifier and compares it to the code_challenge it stored earlier. if the hashed value matches, then only the Authorization Server will return the access_token.

Note

Microsoft identity platform and OAuth 2.0 authorization code flow requires code_challenge_method to be included in the authorization code request ( request to /authorize endpoint). That's basically the method used to generate the code_challenge. This SHOULD be S256, but the spec allows the use of plain if the client can't support SHA256.

And when exchanging authorization code for an access_token (via /token endpoint), client_secret is required for web apps and web APIs as those can store the client_secret securely on the server side. But if the client_secret is sent from a native app, /token endpoint is going to respond with a Bad Request with a message "Public clients should not send a client_secret  when redeeming a publicly acquired grant".

Hope this helps.

Happy Coding.

Regards,
Jaliya

No comments:

Post a Comment