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?