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.