300

With the "Implicit" flow the client (likely a browser) will get a access token, after the Resource Owner (i.e. the user) gave access.

With the "Authorization Code" flow however, the client (usually a web server) does only get an authorization code after the Resource Owner (i.e. the user) gave access. With that authorization code the client then makes another call to the API passing client_id and client_secret together with the authorization code to obtain the access token. All well described here.

Both flows have the exact same result: an access token. However, the "Implicit" flow is much simpler.

The question: Why bother with "Authorization Code" flow, when "Implicit" flow seams to be fine? Why not also using "Implicit" for webserver?

It's more work both for the provider and the client.

itsadok
  • 27,343
  • 27
  • 120
  • 167
Aron Woost
  • 15,276
  • 12
  • 39
  • 49

7 Answers7

331

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.

Nicolas Garnier
  • 11,313
  • 2
  • 38
  • 39
  • 3
    Yeah, got it! The penny dropped with "hash fragment are not part of the HTTP request". Thats right! The hash token never goes over the wire, except from the SSL Resource Server. And you're also saying that the "Implicit" would be possible for servers, if the server would be SSL too, right? So in theory the Resource Server could restrict to redirect url to HTTPS only domains and it would be save (although this is not part of the OAuth2 draft). – Aron Woost Nov 15 '12 at 13:09
  • 1
    Yup correct. The developers' server would need to be SSL thought my personal experience dealing with developers needing SSL certificate (it used to be mandatory to use Google Checkout push notifications in the past) indicated that many-many developers don't have SSL correctly configured. Also to be perfectly safe the SSL certificate should only be issued by a trusted source (not a self-signed certificate because they can be faked), so from Verisign or Comodo... Usually you have to purchase these etc... All these points show that relying on SSL from the common developer would be a huge pain. – Nicolas Garnier Nov 18 '12 at 01:31
  • PS: maybe you want to have a look at this one as well: http://stackoverflow.com/questions/13668361/what-errors-should-be-returned-to-the-3rd-party-application :) – Aron Woost Dec 02 '12 at 10:45
  • "Browsers will pass the hash fragment directly to the destination webpage" -- you mean "will not pass", right? – JW. Sep 14 '13 at 18:38
  • 3
    No: it "will pass" it. I meant what I wrote. What I meant by this is that the hash fragment is kept client side but never sent in the HTTP request (which is readable server side). It is kept client side so basically only readable on the destination webpage using Javascript. – Nicolas Garnier Sep 21 '13 at 23:43
  • 1
    From `The implicit flow is only possible in a browser environment` does this mean that if there are no browsers involved (ie calls between servers kicked off by batch jobs), we would need to use the authorization code workflow? – Sled Mar 18 '14 at 15:12
  • 1
    @AronWoost wrote: **The hash token never goes over the wire, except from the SSL Resource Server**. Isn't it incorrect ? When using a service the "token" is sent from "client" to "resource server" (not from "resource server"). There are these parties: browser, client Web app, resource server, auth server. "hash token" is returned from "auth server" to "client" after authenticating the "user"/"resource owner". In case of "auth code grant" the client is "client web app server", in case of "implicit" the client is "browser". – vlakov Jul 03 '14 at 13:38
  • @Nivco but hash fragment is readable when it is contained in iframe(or when opened in new window) by the parent, no? Does SSL protect from this? – beku8 Aug 29 '14 at 03:42
  • 3
    I understand that this is an old thread but I had a question - About the auth code flow, can't the hacker capture the client id and secret and re-generate the auth code? He will have to sniff two requests to get these details. The first request which generated the auth code will get him the client id while the second one which generated the access token will get him the client secret. Did I misunderstood the flow? – Andy Dufresne Feb 13 '15 at 12:02
  • 17
    @AndyDufresne These two request have to be done over HTTPS (mandatory) since they are requests **to** the OAuth server which has to support only HTTPS. It's only the client/requestor server who do not have to support HTTPS, so only the `Auth Code` is potentially sent in clear over HTTP. But the `Auth Code` is useless without the client ID/Secret. Basically the point of the OAuth Code flow is that the burden of having an SSL-enabled server is on the OAuth Provider (Google/Facebook etc...) and not on the users of the APIs (you, me). – Nicolas Garnier Feb 13 '15 at 13:35
  • 6
    Ok, I now follow that auth code could be passed over plain HTTP and has a risk of getting sniffed. Making it a one time use code and accepting the client secret for exchanging it for an access token, the authorization server could prevent the Man-in-the-middle attack. But doesn't this also apply to the access token? Since the user of the API's could be on plain HTTP, won't there be a risk of the access token be sniffed by the hacker? P.S - I Appreciate your efforts in explaining the concept even after it has been a while since this thread was active. Thanks ! – Andy Dufresne Feb 14 '15 at 11:56
  • 8
    no pb :) The requests to the API - which is when the access token is sent over the wire (to authorize the request) - are also done over HTTPS mandatorily. In theory the client should never be sending the access token over-the-wire in plain HTTP at any moment. – Nicolas Garnier Feb 14 '15 at 21:30
  • 2
    I think I didn't form the question correctly. I understand that the communication flow from the client to the resource server would be over SSL. I was referring to the other communication flow from the resource server to the client. That could be over plain HTTP. Please have a look at the last directed link from resource server to client application in Step 2 in this diagram - http://imagebin.ca/v/1rooU7hybIr0. Won't the access token be on plain HTTP when the resource server sends it the client application? Thank you. – Andy Dufresne Feb 16 '15 at 05:49
  • 5
    The Access Token in this step is part of the response of the HTTPS request from the Client to the resource server. This response is still encrypted. – Nicolas Garnier Feb 16 '15 at 15:36
  • 13
    Basically requests that are initiated from the client to the resource server are done via HTTPS (because the resource owner server has to support supports HTTPS). It's only requests that are initiated from somewhere else to the client that may be done over HTTP (because the client server might not support HTTPS). For instance the redirect that happens during the auth flow after the user grants authorization on the gant page is a redirect initiated from the browser to the client server and may be done in HTTP. – Nicolas Garnier Feb 16 '15 at 15:38
  • 3
    Why not have api respond to authorization_code + server_secret_key, instead of, access_token. So even if authorization code is sent over non HTTPS it's useless without secret key that only the app developer would know. – Muhammad Umer May 24 '16 at 19:58
  • @Nivco I understand the fragment part is not sent to server. But aren't we talking about a redirect call from server to client? In which case the fragment part will be included in HTTP "Location" Header, otherwise how will the browser code at client side come to know about the access token if not transffered by HTTP. – Abhishek Agarwal Jul 03 '17 at 13:07
  • 3
    It's not: After the auth flow the OAuth 2 server returns a redirect. e.g `https://mywebsite.com#access_token=xxx`. Then the browser will send a GET request to load `https://mywebsite.com` (without the hash fragment). Once the page loads the Hash fragment is available for your Javascript code to read but is is never sent to the server via HTTP. – Nicolas Garnier Jul 03 '17 at 13:53
  • 1
    I am wondering how much is this argument still valid? `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` - In the time of services like `let's encrypt` and others having a certificate and configuring it takes minutes if not seconds. – Alma Alma Sep 11 '17 at 12:37
  • Also note that: `authorization code` flow, explicitly calls `auth server` to make sure that `authorization code` originate from `auth server` not from a `Dummy hacker party`. On the other hand `dummy hacker party` cannot request to `auth server` without knowing `client credentials`. – Rzassar Jun 25 '19 at 03:56
  • 1
    @Nicolas Garnier What is the risk of an attacker trying to substitute the identity of the user (Bob) with identity of an attacker (Eve) by replacing the auth code of Bob in relation to Bob's session with Eve's auth code. Here, the auth code is delivered over plain http. Let's assume both Bob's and Eve's auth codes are perfectly valid auth codes in relation to the Client and Client's secret. The "attack" in this case is Bob involuntarily logging in as Eve, where Bob will submit some sensitive information to the Client. After which Even will "legitimately" login to access that data. – Phoeniyx Oct 06 '19 at 23:18
  • There is a few possible security issues with the implicit flow. Two on top of my head: 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). – Nicolas Garnier Oct 17 '19 at 21:10
  • Another issue can happen 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. – Nicolas Garnier Oct 17 '19 at 21:12
  • And of course avoid using non-HTTPS websites since that allows man-in-the middle attack. The auth token in the hash fragment is not readable by intermediary servers BUT an intermediary server could inject a script on your page which would read the token from the hash fragment and send it to the attacker. – Nicolas Garnier Oct 17 '19 at 21:14
  • all very clear. but one thing is not yet quite clear for me. how we protect OTP token then not be be intercepted? we just rely on SSL under the hood? – stdout Feb 12 '20 at 10:06
  • Why is the auth code not sent in hash fragment as well, so that even without https intercepting the auth code itself is also not possible ? – gaurav5430 Oct 26 '20 at 05:43
  • when using https, are the urls also not visible to the intermediate servers / routers ? any examples / articles about how intermediate servers can intercept the url ? – gaurav5430 Oct 26 '20 at 05:43
  • Answering my comment, when using https the urls are encrypted at the transport layer, so the intermediate servers / routers would not be able to intercept the url – gaurav5430 Nov 08 '20 at 19:24
12

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

lakesare
  • 9,453
  • 5
  • 51
  • 65
  • 1
    I would expect that when one has an XSS vulnerability, then even the authorization code flow does not help much. But I agree that since the way how the access token is passed to javascript in the Implicit flow is standardized (as a hash fragment), and if there is XSS vulnerability in the website, then constructing an attack which reads the access token from URL hash fragment is quite easy. With authorization code flow, on the other hand, cross-site request forgery might be possible. – Marcel Mar 05 '18 at 08:41
  • 1
    Also, it is not only about cross-site scripting. Any JavaScript library running in your website could try to steal the access token (for example third party CDN libraries or open source libraries which your javascript framework uses). – Marcel Mar 05 '18 at 08:45
  • 3
    XSS is not a big problem now when we have Content Security Policy headers and Sub Resource Integrity (SRI) hashes. – Sergey Ponomarev Apr 24 '18 at 07:44
5

From the OAuth spec:

4.2. Implicit Grant

The implicit grant type is used to obtain access tokens (it does not support the issuance of refresh tokens) and is optimized for public clients known to operate a particular redirection URI. These clients are typically implemented in a browser using a scripting language such as JavaScript.

Since this is a redirection-based flow, the client must be capable of interacting with the resource owner's user-agent (typically a web browser) and capable of receiving incoming requests (via redirection) from the authorization server.

Unlike the authorization code grant type, in which the client makes separate requests for authorization and for an access token, the client receives the access token as the result of the authorization request.

The implicit grant type does not include client authentication, and relies on the presence of the resource owner and the registration of the redirection URI. Because the access token is encoded into the redirection URI, it may be exposed to the resource owner and other applications residing on the same device.

So what we can consider:

  1. This is for public OAuth i.e. when client not needed to be registered and doesn’t have it’s own client secrets. But what auth server checks redirect url and this is actually enough for security.

  2. The Access token occurs in browser’s address bar so user can copy the url and send to someone else and it also becomes logged as the user i.e. it’s something like Session fixation. But the browser make an additional redirect with replacing history to remove hash fragment from the url. It also possible to a hacker to stole the access token by sniffing a HTTP trafic but this can be easily protected by HTTPS. Some malicious browser extensions can have an access to urls from address bar but this is ultimately bad situation like broken HTTPS cert. And even Auth code flow can’t help here ether. So what I can see is that passing access token via hash fragment of url is absolutely safe.

  3. The separation of ephemeral access token and refresh token are useless when using a HTTPS and to be honest not so useful even on raw HTTP. But the fact that client via implicit flow can’t receive the refresh token is also nonsense.

Thus I think we should introduce a new grant flow “safe implicit” which works strictly over https, allows refresh token (or we should get rid off them at all), and is preferable than Auth Cose grant flow

msanford
  • 10,127
  • 8
  • 56
  • 83
Sergey Ponomarev
  • 2,460
  • 1
  • 28
  • 39
5

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.

Tim Hardy
  • 1,470
  • 13
  • 29
3

My answer is: you can't implement Implicit flow in a safe and simple manner with the web-app server.

Web-app authorization process involves user interaction so Authentication Server should redirect user's browser back to the web-app's target page after user authentication and consent (I don't see any other way to pass user back to the web-app after some interaction with Authentication Server).

So token should be passed to web-app using redirect URL, right?

As @NicolasGarnier explained in his answer and comments there is no way to pass token as an URL fragment - it will not reach web-app server.

And passing token as an URL param of the redirect URL would be unsafe even under HTTPS: if the target page (let it be "greetings page") contains resources (images, scripts, etc) this resources will be obtained by browser through the series of HTTP(S) requests (each of which have Referer HTTP header containing exact URL of the "greetings page" including URL parameters). This is the way token can leak.

So it seems there is no way to pass token in redirect URL. That's why you need second call (either from Authentication Server to the Client (but to which URL?) or from Client to the Authentication Server (the second call in Authorization Code flow))

Lu55
  • 17,620
  • 4
  • 65
  • 60
1

In "Implicit" flow the client (likely a browser) will get a access token via browser redirection (a GET operation). Browser based communication is not safe and your client secret or token can be intercepted or stolen.

In "Authorization Code" flow, the client (usually a web server) does only get an authorization code, again via browser redirection (a GET operation). Then the server exchanges this code with token by making a (non-browser) POST call to the authorization server. Server includes client secret only for token access call.

Note - According to oauth best practices, "clients SHOULD NOT use the implicit grant (response type "token") or other response types issuing access tokens in the authorization response".

Hope this helps.

Nitin Gaur
  • 562
  • 1
  • 8
  • 20
1

For Googlers:

  • You grant access to your Gmail contacts to a 3rd party
  • Access is granted in the form of tokens
  • ANYBODY with a valid token will gain access
  • So you do not want to expose the token, and minimize its transfer
  • With implicit flow the (uncontrolled) browser gets the access token thus putting the token in public
  • With auth code flow the browser only gets a temporary auth code but never the access token, also the auth code is useless without a secret known only to 3rd party and Gmail

Conclusion

  • For an attacker to gain access to your Gmail contacts, it must break into your 3rd party account
  • However, the attacker never gets a hold on the access token thus is unable to perform operations to your Gmail contacts directly
  • You may authorize a 3rd party to access many services, so you do not want to store all the important tokens locally on your computer
  • However, there is one scenario you can only use implicit flow: when the 3rd party runs locally, and does not have a backend to store tokens
  • Then it can only rely on the front-end to store the tokens, which it has little control

Metaphor

  • Implicit flow: YOU ask PROVIDER for a key, YOU store it in your wallet, YOU are responsible to keep it safe, YOU use the key directly with care, and YOU exchange it for a new key in time
  • Auth code flow: YOU ask for a code, code is handed to your VALET, your VALET combines the code and a secret text then exchange it for a key with PROVIDER, YOU ask your VALET to use the key when needed but never sees the key yourself, and your VALET is responsible to exchange new keys
  • Most of the time your VALET is more security-aware than YOU :)
  • When YOU do not have a VALET, YOU are on your own
theaws.blog
  • 2,001
  • 20
  • 19