OAuth 2.0 defines "state" parameter to be sent in request by client to prevent cross-site request attacks. Same is mentioned in OpenID spec for "nonce". Apart from the fact that "nonce" is returned in ID token instead of query parameters, they appear to serve the exact same purpose. If someone can explain why they are separate
-
2just found an incredibly good article that answers the question in deep https://danielfett.de/2020/05/16/pkce-vs-nonce-equivalent-or-not/ – smnbbrv Oct 04 '21 at 10:06
8 Answers
State and nonce seem to be similar. But if you dig deep, you will find that they serve different purposes.
State is there to protect the end user from cross site request forgery(CSRF) attacks. It is introduced from OAuth 2.0 protocol RFC6749. Protocol states that,
Once authorization has been obtained from the end-user, the authorization server redirects the end-user's user-agent back to the client with the required binding value contained in the "state" parameter. The binding value enables the client to verify the validity of the request by matching the binding value to the user-agent's authenticated state
And this is used in authorization request. It enables the client to validate that the authorization response is not altered and sent by the original server which auth. request was sent. In short, it allows the client to cross check the authorization request and response.
(More elaboration : To accept authorization code response, client need to accept a response from authorization server (ex:- In web app, this can be done by a redirect and a form post to back-end). This means, our client application have an endpoint which is open and accept requests. State parameter protect this endpoint by binding original authorization requests to responses. This is CSRF protection.)
Nonce serves a different purpose. It binds the tokens with the client. It serves as a token validation parameter and is introduced from OpenID Connect specification.
nonce - String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. If present in the ID Token, Clients MUST verify that the nonce Claim Value is equal to the value of the nonce parameter sent in the Authentication Request. If present in the Authentication Request, Authorization Servers MUST include a nonce Claim in the ID Token with the Claim Value being the nonce value sent in the Authentication Request. Authorization Servers SHOULD perform no other processing on nonce values used. The nonce value is a case sensitive string
As you can see, nonce value originates from the authorization request and it is generated by the client. And if nonce is included, it will be present in the token. So the client can validate the token it received against the initial authorization request, thus ensuring the validity of the token.
Also, depending on the flow type, nonce can be a mandatory parameter. The implicit flow and hybrid flow mandate nonce value. Both values are generated and validated by client application.
Why state could not be reused?
If an authorization request is captured, then the malicious party can fake the authorization response. This can be avoided by altering state parameter.

- 1
- 1

- 12,193
- 3
- 33
- 46
-
2What would be the downside, if we pass state itself in the ID token as nonce and also outside it. Use the outside one to prevent CSRF and inside one to Bind session on client side. – dvsakgec Feb 21 '18 at 17:56
-
1@dvsakgec From protocol perspective, what matter is utilising state and nonce for security & validations. As far as I know specs doesn't restrict you from using same value for state and nonce. In a sophisticated attack vector, one may be able to extract state value from authorisation response (ex:- mobile application). So having the same values remove one condition from your token validation process, which is not good – Kavindu Dodanduwa Feb 22 '18 at 03:19
-
3Sorry for being late, but for argument that state parameter can be taken out from response completely kills the purpose of state parameter. Also, if same parameter is used in both then in case of OpenID Connect flow, sophisticated attack won't work as ID token collected from back channel call will have the same parameter and client can compare the state parameter from both calls to check validity of the call made earlier. – dvsakgec Jul 13 '18 at 06:12
-
@KavinduDodanduwa Thanks for the good explanation. Nonce seems to be much more secure, so why do we need to put a state parameter in, if it will be manipulated, and we can put the nonce parameter in? – Avi Siboni Nov 05 '20 at 07:46
-
3@avisiboni to accept authorization code response, client need to accept a response from authorization server (ex:- In webpage, this can be done by a redirect and a form post to back end). This means, our client application have an endpoint which is open and accept requests. State parameter protect this endpoint by binding original authorization requests to responses. This is CSRF protection. Nonce is totally different and both server different purposes. – Kavindu Dodanduwa Nov 05 '20 at 08:48
-
Nonce answers the question to the browser: Is this ID token a response to my initial request?
State answers to the backend server: did the consent really come from who I think it did?
So they answer similar questions but to different entities.

- 18,827
- 15
- 113
- 136
-
5Isn't that the contrary? As I understand, `state` is used in the browser, and `nonce` in the server. – Rafael Eyng Jul 26 '20 at 23:43
-
@RafaelEyng you migh be right. It was a long time I dwelled into this. Probably some reference would help out. Beside the naming though, their functionality is as mentioned. – Pithikos Aug 13 '20 at 14:05
I am stating an explanation from their RFCs. The explanation is pretty straightforward.
State
An opaque value used by the client to maintain state between the request and callback. The authorization server includes this value when redirecting the user-agent back to the client. The parameter SHOULD be used for preventing cross-site request forgery
Nonce
The nonce parameter value needs to include per-session state and be unguessable to attackers. One method to achieve this for Web Server Clients is to store a cryptographically random value as an HttpOnly session cookie and use a cryptographic hash of the value as the nonce parameter. In that case, the nonce in the returned ID Token is compared to the hash of the session cookie to detect ID Token replay by third parties. A related method applicable to JavaScript Clients is to store the cryptographically random value in HTML5 local storage and use a cryptographic hash of this value.
Reference Link: State: https://datatracker.ietf.org/doc/html/rfc6749
Nonce:https://openid.net/specs/openid-connect-core-1_0-17_orig.html
Hope this answers your question.

- 349
- 2
- 12
-
5Just a -1 because I think the OP was moreso asking for an explanation of the difference in how the two are meant to be used, rather than a snippet of the RFC. – rurouniwallace Apr 10 '20 at 00:22
-
3As I mentioned in my answer that the snippet from RFC is self explanatory. – Mayur Dighe Apr 11 '20 at 14:48
-
23"Self explanatory" is a very subjective thing. I've read the specs and still didn't get the difference. Don't assume the same level of understanding as you have from a person who is exactly asking a question about a subtlety. – Rafael Eyng Jul 26 '20 at 23:50
-
1
-
How can a concept of unique identifies in each request be tied to type of a client, in the end is it not the case where there is a variable containing unguessable value to identify each request. Why we not try to link both concepts and question it rather eating up the RFC in breakfast. – dvsakgec Aug 26 '20 at 10:41
-
-
-
1@MayurDighe I do. But this answer would be great if you added links. It would greatly improve the quality of the answer, IMO. – TheMaster Mar 07 '21 at 18:34
Adding to the above answers which focus on the security aspect of state
and nonce
, if you're implementing your own 3-legged OAuth2 workflow (client, your middleware and a Federated Identity Provider such as Facebook), your middleware might sometimes need some context. For example, when the response from the FIP reaches back to your middleware before going back to your client, you may need to know more about the details of the original request (i.e., the original request to the FIP). Because your middleware is most likely stateless, it won't be able to answer that question without any help. That's where the OAuth2 state
variable comes in. You could store any string that represents the state you want to pass between all the OAuth2 jumps so that your middleware (as well as your client) can use some more context. In the case of your client, this is used for security reason. The nonce
is used as part of the OIDC specification for pure security reasons.

- 987
- 12
- 22
Actually "NONCE" is enough to validate sender and response. But before you should open the token to read "NONCE". beacuse of this you have to accept response if there are millions fake respose you will accept all of those to open token and read "NONCE". But state is allready opened on response header, you can easly read state and easly reject fake response. this is two level ceheck.

- 79
- 1
- 2
As a MiiT actor, Mallory intercepts the ID token somehow and relays the token to Relying Party (aka protected service, resource server). Relying Party denies the ID token because no session cookie in Mallory's browser. The simplified relation between nonce and session, nonce = hash(session, seed_rotated_regularly)
State is a CSRF token generated by relying party in every HTTP response. As a user, Alice clicks a phishing link accidentally and her user agent is redirected to the authentication service (aka OP, IdP). Thanks to single sign-on, Alice does not notice the HTTP 302 back and forth. Assume the phishing website is allowed in redirect_uri. Relying Party can deny the HTTP request with a valid token obtain by the phishing website because state is not presented. Nonce does not work in this case because session cookie is in Alice's user agent. State cannot prevent MiiT because Mallory can get the token, state, but not the session cookie.

- 21
- 2
To demonstrate the difference, let's consider a situation where state
exists but nonce
doesn't and the attacker is able to intercept the authentication response (redirection from the Authorization Server or OIDC Provider to the client) and inject a malicious authorization code with the same state
parameter. This is more likely to happen for native applications and can be mitigated by using nonce
parameter approach.
OR the attacker can easily use the intercepted authorization code on the attacker's client application to log in to the victim's account. (This can also happen if nonce
exists because the attacker can alter the client application to bypass nonce
checking. This should be prevented by the authorization server or OIDC Provider by detecting multiple usages of the same authorization code or giving exact same consent in a short time)
PKCE can also be used as a sophisticated method, but all of the authorization servers or OIDC Providers may not support it.

- 161
- 1
- 11
This is my understanding of State
vs Nonce
. I am not sure if it is 100% accurate, so let me know if anything needs adjustment. Hopefully this helps.
State
- OAuth 2.0: HTTP CSRF Token only
- OIDC 1.0: HTTP CSRF Token, and session ID to lookup
Nonce
for comparing to ID Tokennonce
claim
Nonce
- OAuth 2.0: Not part of the specification because opaque tokens (i.e. no JWTs => no
Nonce
claims) - OIDC 1.0: ID Token claim
State (OAuth 2.0)
User Agent calls Authz Client twice in OAuth 2.0 Authz Code Grant Flow. For example:
- Start flow:
http://authzclient/start
- Finish flow:
http://authzclient/finish?state=AUTHZ_CLIENT_CSRF&code=AUTHZ_SERVER_CODE
Response 1 points to Authz Server, with redirect_uri and State to point User Agent back to Authz Client.
http://authzserver/authorize?redirect_uri=http://authzclient/finish?client_id=client1&state=AUTHZ_CLIENT_CSRF&response_type=code&scope=SCOPE1%20SCOPE2
Notice there is no openid scope and no nonce parameter. This example is OAuth 2.0 only, not OIDC 1.0.
As a CSRF Token, it doesn't matter if many Authz Server calls happened between the two Authz Client calls. State is still valid as a CSRF Token for the second request to the Authz Client (e.g. a Web Server).
State (OIDC 1.0)
State is used as an ephemeral CSRF Token just like in OAuth 2.0. However, it seems OIDC 1.0 reuses it as a long term Authz session ID too. For example, State is used to validate a Nonce claim in an ID Token.
Nonce is not part of OAuth 2.0. The original OAuth 2.0 said to use opaque Access Token and Refresh Token (i.e. not JWTs). When Nonce was added, I think that is where State was given a second purpose.
Nonce (OIDC 1.0)
Adding an openid scope and Nonce parameter to the previous example response makes it OIDC 1.0 now.
http://authzserver/authorize?redirect_uri=http://authzclient/finish?client_id=client1&state=AUTHZ_CLIENT_CSRF&response_type=code&scope=openid%20SCOPE1%20SCOPE2&nonce=CLIENT_NONCE_CLAIM
The Authz Client:
- receives Authz Code and State query parameters from User Agent
- verifies if State matches any existing (i.e. unfinished) flow
- receives ID Token (with Nonce claim) from Authz Server
- uses State query parameter as a session ID, to lookup Nonce value generated at same time as State
- verifies Nonce from the session matches the nonce claim in the ID Token
During the flow, the State is used to do a lookup of the original Nonce for validating the ID Token.
After the flow, the ID Token nonce claim can be used to do a reverse lookup to get the original State. That points to the original Authz Session, which may contain extra information not in the ID Token.

- 646
- 5
- 7