https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-30#section-10.12 says:

The client MUST implement CSRF protection [...] typically accomplished by requiring any request sent to the redirection URI endpoint to include a value that binds the request to the user-agent's authenticated state (e.g. a hash of the session cookie [...]

It doesn't say much about the implementation, though. It only puts some light on how the CSRF works:

A CSRF attack against the client's redirection URI allows an attacker to inject their own authorization code or access token, which can result in the client using an access token associated with the attacker's protected resources rather than the victim's (e.g. save the victim's bank account information to a protected resource controlled by the attacker)

But use of the word "rather" rather makes the statement worthless.

I am thinking how to implement the "state" in GAE (using Webapp2). It would be easiest starting at how a hacker could use a CSRF against OAuth2. I found only one good article about the matter: "Cross Site Request Forgery and OAuth2".

Unfortunately, while this blog post is well written, there's not much information beyond explaining the OAuth2. The examples don't work, and I don't know Spring. Still, I found one interesting recommendation there: the server connecting to an OAuth2 provider should store "state" as a random session key (e.g. "this_is_the_random_state":"this_doesn't_matter"), and not a value under a static key (e.g. "state":"random_state_string").

My question is, what's the sane implementation of the "state"?

  • Should the randomly generated state be hashed, or can the same value be stored and sent to the OAuth2 provider?
  • Is there a difference here if the session backend is secure cookies or a server-side storage technology (e.g. in GAE Memcache, or database)?
  • Should state be stored as a key as suggested?
  • Should state has validity period, or is session (if there is one) lifetime enough?

4 Answers 4


I will simplify this problem. Cross-Site Request Forgery and Clikjacking attacks are useful because it can force a victim's browser into performing actions against their will.

The mention of 10.12. Cross-Site Request Forgery and 10.13. Clickjacking in the OAuth v2 RFC have fundamentally the same concern. If an attacker can force a victim's browser into authenticating, then it is a useful step in forcing the victim's browser into performing other actions.

   in a clickjacking attack, an attacker registers a legitimate client
   and then constructs a malicious site in which it loads the
   authorization server's authorization endpoint web page in a
   transparent iframe overlaid on top of a set of dummy buttons, which
   are carefully constructed to be placed directly under important
   buttons on the authorization page.  When an end-user clicks a
   misleading visible button, the end-user is actually clicking an
   invisible button on the authorization page (such as an "Authorize"
   button).  This allows an attacker to trick a resource owner into
   granting its client access without their knowledge.

Source: 10.13. Clickjacking

For example, Stack Overflow uses OAuth and is vulnerable to this attack. If you visit StackOverflow and you are currently logged into your OAuth provider, you will be automatically logged in to StackOverflow. Therefor an attacker could automatically log in a victim by loading Stack Oveflow within an iframe. If Stack Overflow also had a CSRF vulnerability (and it has had them!), then an attacker could automatically authenticate a victim's browser and carry out a CSRF (Session Riding), Clickjacking, or XSS attack against stackoverflow.com in a Chained Attack.

  • Thanks. I've done such XSRF (CSRF) attacks (e.g. I sent a link to my friend that made him delete a post on his forum), and I imagine an attack where someone gives you a login URL to a site, where you login as him (victim logs in on attacker's account). It's quite easy to protect against such attack (store state in session), but aren't there more complex hacking techniques than that? Commented Oct 2, 2012 at 17:31
  • @Markus von Broady Clickjacking, Chaining and XSS is really as complex as attacks get for this RFC violation. There is really no other point in establishing a session for a victim unless you plan on riding on it with other attacks. If you had an XSS vulnerability in SO, this would be a pretty clean account hijack, which is nasty.
    – rook
    Commented Oct 2, 2012 at 17:56
  • 8
    I do not completely agree with the explanation given by @rook about the potential impact of a successful CSRF attack against the Oauth redirection URI. The point is that an attacker can trick a client (which is running on behalf of the victim) into acquiring an access token that is linked to the attacker (and not to the victim). The impact is that a victim potentially saves sensitive data using an access token that is linked to the attacker: the attacker can then easily access the victim's data at the client by logging in to the external identity provider (source: oauth threatmodel).
    – Michael
    Commented Jan 29, 2016 at 16:28
  • @rook Is it okay to use existing CSRF token (UUID) as state param, CSRF token is is getting generated when user is logging into the web application? Is there any security vulnerability will happen If I share CSRF token with third-party systems like OAuth provider? My question here stackoverflow.com/questions/74917368/…
    – Amogh
    Commented Jan 2, 2023 at 7:51
  • 1
    @Amogh this is generally a bad idea because it increases the likelihood of the token getting leaked and then re-used elsewhere. You can make a site-specific or zone-specific CSRF token by taking a hash(UUID,secret) and using that as a temporary token.
    – rook
    Commented Jan 16, 2023 at 6:51

Let's walk through how this attack works.

The Attack

  1. I visit some client's website and start the process of authorizing that client to access some service provider using OAuth

  2. The client asks the service provider for permission to request access on my behalf, which is granted

  3. I am redirected to the service provider's website, where I would normally enter my username/password in order to authorize access

  4. Instead, I trap/prevent this request and save its URL

  5. I somehow get you to visit that URL instead. If you are logged-in to the service provider with your own account, then your credentials will be used to issue an authorization code

  6. The authorization code is exchanged for an access token

  7. Now my account on the client is authorized to access your account on the service provider

So, how do we prevent this using the state parameter?


  1. The client should create a value that is somehow based on the original user's account (a hash of the user's session key, for example). It doesn't matter what it is as long as it's unique and generated using some private information about the original user.

  2. This value is passed to the service provider in the redirect from step three above

  3. Now, I get you to visit the URL I saved (step five above)

  4. The authorization code is issued and sent back to the client in your session along with the state parameter

  5. The client generates a state value based on your session information and compares it to the state value that was sent back from the authorization request to the service provider. This value does not match the state parameter on the request, because that state value was generated based on my session information, so it is rejected.

Your Questions

  • Should the randomly generated state be hashed or can same value be stored and sent to OAuth2 provider?

The point is that the attacker should not be able to generate a state value that is specific to a given user. It should be unguessable.

  • Is there a difference here, if session back-end is secure-cookies or a server-side storage (in GAE Memcache or database)?

I don't think this matters (if I understand you correctly)

  • Should state be stored as a key as suggested?

I don't know what this means.

  • Should state has validity period, or session (if there is one) lifetime is enough?

Yes, state should have an expiration. It doesn't necessarily have to be tied to the session, but it could be.

  • 1
    From what I read, the state should be generated randomly. You suggest something opposite - to generate it from user data. I also don't understand why the hash should be unique - how do one enforce the uniqueness of a hash? Commented May 15, 2014 at 16:14
  • It depends on what you mean by random. The client must be able to generate the state for a user and then independently re-create that state later, so that it can compare the two. If it's just random, then how would you compare the them? Also, the reason to generate it from user data is that we're trying to identify a user.
    – Wayne
    Commented May 15, 2014 at 16:16
  • 1
    I don't recreate it, I store it on the server. Commented May 15, 2014 at 16:19
  • 10
    Correct me if I'm wrong, but the attack description makes a big assumption that the service provider URL used by the victim contains state that would link the redirect to your own account on the client. Most OAuth client implementations I've seen would not trust this state.
    – emagdne
    Commented Jan 28, 2019 at 16:28
  • 1
    wrong! In step5 - when I click your url, I'm on my browser, authorization code used to exchange the token. But how is this token linked to your account since on my browser only I could have been logged in to client. So the token will be linked to my account only not yours. Then how will your account on client is authorized to access my account on resource server? Does not make any sense.
    – VVK
    Commented Mar 16, 2022 at 19:09

Taken from The Importance of the state parameter in OAuth2:

This is where the "state" object in OAuth 2 comes into play. By always submitting a non-­guessable state when POSTing to the authorization endpoint, the client application can be certain that the Access Code obtained from the Authorization Server are in response to requests made by it rather than some other client application.



For the state parameter to be useful in preventing CSRF attacks like this, all requests made to the OAuth server must include a state parameter that the client can use to authenticate itself. When sending a state parameter, the OAuth spec stipulates that the Authorization Server must return it to the client verbatim. This will be done by tacking it onto the client's call-back URL. The client must receive this state and be programmed to only accept redirects with a verifiable state. If this is a dictionary kept in memory or a re­-computable value is up to the client programmer.

When deciding how to implement this, one suggestion is to use a private key together with some easily verifiable variables, for example, client ID and a session cookie, to compute a hashed value. This will result in a byte value that will be infeasibility difficult to guess without the private key. After computing such an HMAC, base-64 encode it and pass it to the OAuth server as state parameter. Another suggestion is to hash the current date and time. This requires your application to save the time of transmission in order to verify it or to allow a sliding period of validity (e.g., using TOTP).

Here is a simple Python example that uses the second suggestion using datetime:

def generate_state_parameter(client_id, private_key):
    date = datetime.datetime.today()
    raw_state = str(date) + client_id
    hashed = hmac.new(private_key, raw_state, sha1)
    state = base64.b64encode(hashed.digest())
    return (state, date)

In addition to @wayne's answer, here is a different possible attack (that could have been prevented with the use of CSRF tokens stored as cookies):

  1. Attacker gets an OAuth authorization code for their own account ;
  2. Attacker tricks user into following redirection link, with the attacker's authorization code ;
  3. User gets logged in to the application, thinking it's their own account when it is actually the attacker's account.

If the application in question displayed, for example, the bank details of an account where money should be transfered to, then that can be a major problem.

A CSRF token stored in session cookies would have prevented this. Because the CSRF token is stored as a cookie, the attacker cannot trick the user into using the attacker's CSRF token. When logging in with the attacker's OAuth code, the user would still have sent their own CSRF token. The application server would have noticed the OAuth code and the CSRF token don't match, would have refused the authentication from the user.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .