Why do we require clients to include the redirection URI when exchanging an authorization code for an access token in OAuth 2.0 (section 4.1.3)?
Consider the following scenario:
- Evil user starts the OAuth flow on a legitimate client using the authorization code grant type flow.
- Client redirects the evil user to the authorization server, including state information about the evil user account on the client.
- Evil user takes the authorization endpoint URI and changes the redirection to its evil site.
- Evil user tricks victim user to click on the link and authorize access (using phishing or other social engineering methods).
- Victim user thinking this is a valid authorization request (it looks kosher), authorizes access. Access is granted to the right legitimate client. So far nothing is wrong.
- Authorization server thinks it is sending victim user back to the client, but since the redirection URI was changed, victim user is sent to the evil site.
- Evil user takes the authorization code and gives it back to the client by constructing the original correct redirection URI.
- Client exchanges the code for access token, attaching it to the evil user’s account.
- Evil user can now access victim user data via his client account.
The way this works, the attacker does not get direct access to protected resources, but it tricks the client into attaching the victim’s access token to the attacker’s account.
Pre-registration of the redirection URI can help a lot, but depends on the matching rules. Since many large providers have open redirectors, the attacker can use those to construct a redirection URI that passes the authorization server validation.
Requiring clients to register their full redirection URI without allowing any variations or partial matching is highly recommended.