Why is there an "Authorization Code" flow in OAuth2 when "Implicit" flow works so well?

tl;dr: This is all because of security reasons.

OAuth 2.0 wanted to meet these two criteria:

  1. You want to allow developers to use non-HTTPS redirect URI because not all developers have an SSL enabled server and if they do it's not always properly configured (non-self signed, trusted SSL certificates, synchronised server clock...).
  2. You don't want hackers to be able to steal access/refresh tokens by intercepting requests.

Details below:

The implicit flow is only possible in a browser environment because of security reasons:

In the implicit flow the access token is passed directly as a hash fragment (not as a URL parameter). One important thing about hash fragment is that, once you follow a link containing a hash fragment, only the browser is aware of the hash fragment. Browsers will pass the hash fragment directly to the destination webpage (the redirect URI / the client's webpage). Hash fragment have the following properties:

  • They are not part of the HTTP request therefore they can't be read by servers and because of that they cannot be intercepted by intermediary servers/routers (this is important).
  • They only exist on the browser - client side - so the only way to read the hash fragment is using JavaScript that runs on the page.

This makes it possible to pass an Access Token directly to the client without the risk of it being intercepted by an intermediary server. This has the caveat of only being possible client side and needs javascript running client side to use the access token.

The implicit flow also has security issues that requires further logic to workaround/avoid for instance:

  • An attacker could get an access token from a user on a different website/app (let's say if he is the owner of the other website/app), log the token on their website, and then pass it as a URL param on your website therefore impersonating the user on your website. To avoid this you need to check the Client ID associated with the access token (for instance for Google you can use the tokeninfo endpoint) to make sure the token was issued with your own client ID (i.e by your own app) or check the signature if you are using an IDToken (but that requires your client secret).
  • If the auth request did not originate from your own property (called Session Fixation attacks), to avoid this you'll want to generate a random hash from your website, save it in a cookie and pass that same hash in the state URL param of the auth request, when the user comes back you check the state param with the cookie and it must match.

In the authorization code flow it is not possible to pass an access token directly in a URL parameter because URL parameters are part of the HTTP Request, therefore any intermediary server/routers by which your request would pass (could be hundreds) could be able to read the access token if you are not using en encrypted connection (HTTPS) allowing what's known as Man-in-the-middle attacks.

Passing the access token directly in a URL param could in theory be possible but the auth sever would have to make sure the redirect URI is using HTTPS with TLS encryption and a 'trusted' SSL certificate (typically from a Certificate Authority that is not free) to be sure that the destination server is legitimate and that the HTTP request is fully encrypted. Having all developers purchase an SSL certificate and properly configure SSL on their domain would be a huge pain and would slow adoption down tremendously. This is why an intermediary one-time-use "authorization code" is provided that only the legitimate receiver will be able to exchange (because you need the client secret) and that the code will be useless to potential hackers intercepting the requests over unencrypted transactions (because they don't know the client secret).

You could also argue that the implicit flow is less secure, there are potential attack vectors like spoofing the domain upon redirect - for example by hijacking the IP address of the client's website. This is one of the reasons why the implicit flow only grants access tokens (which are supposed to have a limited time use) and never refresh tokens (which are unlimited in time). To remedy this issue, I advise you to host your webpages on an HTTPS-enabled server whenever possible.


The Implicit Flow makes the whole flow pretty easy, but also less secure.
As the client application, which is typically JavaScript running within a Browser is less trusted, no refresh tokens for long-lived access are returned.
You should use this flow for applications that need temporary access (a few hours) to the user’s data.
Returning an access token to JavaScript clients also means that your browser-based application needs to take special care – think of XSS Attacks that could leak the access token to other systems.

https://labs.hybris.com/2012/06/05/oauth2-the-implicit-flow-aka-as-the-client-side-flow


For us, our clients wanted to be able to authenticate with our app on their phones once, and not have to log in again for weeks at a time. With code flow, you get a refresh token along with your access token. Implicit flow does not give you a refresh token. The access token has a relatively short expiration, but the refresh tokens can have up to a 90 day expiration. Whenever the access token expires, the client and server code can use that refresh token to get a new access token plus refresh token, all behind the scenes, without any user intervention whatsoever. A refresh token can only be used once. You cannot do this with Implicit Flow. If you're using Implicit Flow, and your user doesn't interact with your app for over an hour, they will have to log in again when they come back. That was not acceptable in our use case, and Code Flow supports our use case securely.

This works and is secure because refresh tokens can be revoked. If a customer says they lost their phone or their laptop or a hacker got on to their desktop, we can simply revoke all of the refresh tokens for that user. During the entire process, no Personally Identifiable Information (PII) ever touches our code - namely the user's password.

Code flow is awesome, but it does take more work. MS does not have an Angular library to handle it currently, so I had to write one. If you are interested I can help you with it.