Reputation: 6162
I am trying to understand the various grant types offered by OAuth2.0. I have been reading up on it & there are a lot of resources that explain it in good details, like this, this & this to quote a few.
In case of authorization code grant type, from my understanding there are 2 steps.
Step 1 - To get the authorization code itself
So let's assume that the user opens the application, say AwesomeApp
in their browser. This app has an option like say Login with Facebook, which the user chooses to go ahead with. This initiates a GET request made to the authorization server (of Facebook in our example) with the needed details in the query parameter, something like (taken from one of the resources linked above):
https://authorization-server-of-facebook.com/auth?response_type=code&
client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos&state=1234zyx
Now I understand the meaning of each of those parameters (thanks to the resources again). I also understand that before the AwesomeApp
could make this call, it must have registered with Facebook to receive a client ID & client secret (through some means).
Now once the user approves the request facebook's authorization server responds to the above request by redirecting the user's browser back to the redirect uri that was provided (in the above request) & with the authorization code.
Step 2 - To exchange the authorization code for the actual access token
Now AwesomeApp
needs to exchange the authorization code received above for an access token. To do this AwesomeApp
makes a POST request like the below:
POST https://api.authorization-server-of-facebook.com/token
grant_type=authorization_code&
code=AUTH_CODE_RECEIVED_IN_THE_ABOVE_STEP&
redirect_uri=REDIRECT_URI&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET
To the above request the authorization server of facebook returns back an access token, a refresh token an expiry time etc. etc.
Now my question is in the step 2 above. Shouldn't this POST be a backend call? Why? Because it requires the client secret to be sent across in the request as well. If it were to be done from the front end of AwesomeApp
, it would easily be leaked to a spurious user. Isn't it?
So I was thinking, it should be something like once AwesomeApp
receives the authorization code, the frontend of AwesomeApp
should send this over to it's own backend & then AwesomeApp
's backend should make the above POST request, retrieve the access token (& other details) from the response of the above request & then pass it on to it's frontend. Is this not how it should be?
Now in most of the resources that I came across (including the above links), it discusses about PKCE Extension
which talks about generating a dynamic client secret every time. But how is it any better if the POST (the one in the step 2) is still done from the front end itself? Also if this client secret is dynamically generated every time, it could be done by a spurious user as well, isn't it. I mean how would the authorization server validate that the client making the request was indeed the one that it had allowed? (In the client secret case it made sense, because the client secret was given to AwesomeApp
by Facebook's authorization server. In this case it doesn't, because this secret is being generate by the client itself).
What am misunderstanding in all of the above?
As per the flow explained here, , how does the code_verifier
prevent an adversary to play as a genuine app? Unlike with client secret, where the attacker would never be able to impersonate a genuine client (unless of course the client secret itself is somehow compromised), in this case, the attacker could simply send any code_verifier
. Before even the token request & verification of the code_verifier
& the final response comes into the picture, how would the authorization server even validate that the authorization request indeed came from a genuine client?
Upvotes: 2
Views: 1302
Reputation: 23436
You understand the authorization code flow correctly. In the original OAuth2 spec, the code flow was intended for confidential clients (i.e traditional web applications running on a server). Implicit flow was intended for applications running inside the browser like Single Page Applications. Implicit flow delivers the access token to the client directly via the redirect URI.
Now implicit flow was vulnerable to token leakage (referrer headers and server logs), so PKCE was invented to use code flow for public clients also. It generates a hashed value from an identifier called verifier
and sends it with the authorization request. When the client gets the code, it uses the verifier as the secret to prove to the authorization server it was the client that made the original authorization request (to which the user signed in).
Even though a malicious client can generate authorization request, the user needs to sign in and consent to the client getting an access token to access their data. If the user decides to trust the malicious client, there's nothing the protocol can do since the client does not have to authenticate itself.
Upvotes: 1