What is the purpose of the 'state' parameter in OAuth authorization request
Asked Answered
J

5

68

In OAuth, the initial authorization request has a state parameter. Apparently it's there for security reasons, but I don't really understand against what it protects... For instance, on GitHub the description of this parameter is:

An unguessable random string. It is used to protect against cross-site request forgery attacks.

From what I can see, the state from the authorization request is just passed as a parameter to the redirect URL like this:

http://<redirect_url>?code=17b1a8df59ddd92c5c3b&state=a4e0761e-8c21-4e20-819d-5a4daeab4ea9

Could someone explain the exact purpose of this parameter?

Jasminjasmina answered 30/9, 2014 at 23:48 Comment(4)
See also csrf - OAuth2 Cross Site Request Forgery, and state parameter - Information Security Stack ExchangeGrisby
I found this great article while searching for the same question: medium.com/@benjamin.botto/…Schear
I wouldn't be surprised if this were some sort of relic as it can't possibly be used for any CSRF protection considering it is passed as a GET request parameter but not in the cookies so it does not fulfill the Double Submit Cookie pattern requirements.Bowline
While looking around some more, it almost seems like the purpose of this parameter is less for CSRF protection but for the client requesting auth to ensure that the response is truly for the request they made. Which seems completely useless. Any MITM attack could easily intercept this. What is really needed then should just be HSTS.Bowline
C
67

The state parameter is used to protect against XSRF. Your application generates a random string and sends it to the authorization server using the state parameter. The authorization server sends back the state parameter. If both state are the same => OK. If state parameters are different, someone else has initiated the request.

The example from Google is maybe clearer: https://developers.google.com/accounts/docs/OAuth2Login?hl=en#createxsrftoken

Creon answered 1/10, 2014 at 0:58 Comment(8)
"someone else has initiated the request": thanks, that's what I was missing. I'm not in the context of a web app, so it doesn't apply to my case (I just detect the redirect in a WebBrowser control in a desktop app, no one is going to send requests to me...)Jasminjasmina
The developers of ckanext-oauth2 use the state parameter also to store info about the previously visited page, to redirect the user back there after login, e.g.: {"came_from": "/dashboard"}. They base64 encode it to make it URL-safe and then use it for the state parameter.Beverlee
@Beverlee wouldn't that be guessable?Dickie
@SriramKailasam, yes you are right, it is guessable. You are right that came_from is not suited as XSRF token. But I think in the case of this plugin they don't use the state parameter for a XSRF token. I don't think there is anything keeping you from storing a XSRF token, plus something like e.g. came_from in the state parameter.Beverlee
You missed a really important point, the state parameter should be somehow tied to your session.Crowned
Would you say this is only necessary for applications that require really high security? Or should every app/website that uses Google oauth2 implement this? After all, it's optional.Carpophagous
Hi, can I use CSRF token for state parameter? My application is already generating UUID as CSRF token, so while making OAuth request can I use the same UUID for state param. I have asked similar question #74917868Torto
This seems like some really useless CSRF protection. If the token is passed in the request like that, then it can just be copied by anyone. It is only useful if a cookie is also passed with it for the Double Submit Cookie pattern.Bowline
A
15

state is echoed back in the query string sent to the redirect_uri. It has two purposes:

  1. The original use, as per its name is to transmit state information from the initiating webpage to the redirect_uri. For example, I have a process that sends users a link that allows them to link their account to some other resource. The link contains information (a token) that describes that resource. So the user clicks the link and they are taken to a web page, where they are redirected to the authentication server. I need that token to make its way through the authentication process back to the redirect_uri, so that the business logic behind the redirect_uri can finish linking the resources to the users account. I do this by using "state" to carry that information. Given "state" has no size limit, if can be used to carry all sorts of very useful information.

  2. As a means to protect against XSRF... It is very easy for a third party to forge a request to the authentication server and trick your redirect_uri into accepting the response. If the state information is a randomly generated value and the redirect_uri is in some way able to validate it as being its own, then you can protect yourself against this.

It is a misconception that the random value must be bound to or stored in some session. Though this is a valid way of verifying the state, it is flawed. If there is a delay in authentication (for example a user hanging in the login screen for several hours), then such a validation method would fail if the session had expired. It would also fail if the user had initiated multiple logins by mistake or by double clicking.

It is far better imho to use a private key to sign the random value. For example take the SHA1 or SHA256 hash of a random number + the private key as the signature. Make the state value a combination of the the random number and the signature. Noting that you would convert the binary value to Base64. It is common to use a full stop as a separator in the same manner as a JWT:

signature = BASE64_SHA256(random + privateKey)
state = random + "." + signature

You verify this by splitting the state value at the full stop as follows:

verifyValue = BASE64_SHA256(split(state,".")[0] + privateKey)

If verifyValue = split(state,".")[1] then the state is valid. No pesky session storage, so validation is much faster.

It is perfectly feasible to combine the two purposes into one. That is you can take the known value that you want your redirect_url to know about, add the random number and then add the signature as a SHA256 hash of both values. E.g:

signature = BASE64_SHA256(data + "." + random + privateKey)
state = data + "." + random + "." + signature

This is super secure because all the state information is fully signed and protected, which doesn't happen if you use a simple security token stored against the session (as per the method in OpenID Connect: Create an anti-forgery state token)

10/11/2023: IMPORTANT Addendum

The privateKey is server side. So this method is suitable for Step A of Authorization Code Grant as per RFC 6749:

In the initiating step A you need to post a request to your own server to generate the signed state field. Your server returns a 303 redirect with Location: set to the authentication server with the signed state field.

For example:

HTTP/1.1 303 See Other
Content-Type: text/html;charset=ISO-8859-1
Location: https://authenticate.somehost.com/Authenticate/?client_id=someid&redirect_uri=https://www.myhost.com/returnpage&state=FFcI1gmokWkJpjjy3pG6WPl7KryZVxPGSOx9F4WvaY8.gcnIBIUpBzOh3e-iwUq1Y_gsK-Y5SCSS3ahGrIaU6zQ&code_challenge=dOTqvgv0B5p4Nur2RrkWjysAMCSNaeu73pv3xWBBWPQ&code_challenge_method=S256
Ankeny answered 2/9, 2023 at 20:5 Comment(0)
P
0

To add to @CaptainBeOS answer, using a private key would probably not work if it is hardcoded into the application on the client side (e.g. browser), because if anyone (attacker) can see this private key by loading the webpage, they can just as well do the first step of encoding random + signature and this will verify correctly each time as it is no different from signing this yourself. Therefore either you need to store the signature in the session (at which point why bother), or you need to give a new private key every time to a new browser. That also relies on the private key being stored in each session or on the backend to fetch.

Pall answered 6/9, 2023 at 9:22 Comment(1)
This is accurate, but it's worth clarifying that if an attacker can see your private key then it isn't private.Neume
S
0

One line answer

Purpose of state parameter in OAuth authorization request

It help to protect from cross-site protection.

Detailed Answer

The 'state' parameter in OAuth authorization requests serves as a crucial security measure to protect against various attacks, including cross-site request forgery (CSRF) and unauthorized code exchanges. Its primary purposes are:

1. Preventing unauthorized code exchanges: By including a randomly generated 'state' value in the authorization request and verifying it when the authorization code is returned, the client can ensure that the received code corresponds to its original request.

2. Mitigating CSRF attacks: The 'state' parameter helps prevent attackers from tricking the client into processing authorization codes that it didn't initiate.

3. Protecting against session fixation: By validating the 'state' value, the client can detect potential session fixation attempts.

4. Resource conservation: It prevents attackers from using the client to fish for valid authorization codes, which could waste both client and server resources.


Follow the below steps to implement this protection:

1. The client generates a random 'state' value before initiating the authorization request.

2. This value is included in the authorization URL sent to the authorization server.

3. The authorization server must return the 'state' value unchanged alongside the authorization code.

4. The client verifies that the returned 'state' matches the original value.

5. If the 'state' values don't match, the client halts processing and displays an error.

Note: While optional, using the 'state' parameter is considered a best practice in OAuth implementations to enhance security and prevent potential exploits.

Sensillum answered 3/7 at 6:20 Comment(0)
B
-1

The only seemingly useful purpose I've come up for the presence of the state paremetr is to encode information about the user so that you know which user to associate the response you are getting to.

Then, upon a successful request to your callback endpoint, you could decode the returned state parameter, verify the info passed corresponds to your callback's logged in user info, and then proceed to get the auth token.

Bowline answered 6/9, 2023 at 15:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.