How to do request_uri single use? Pushed Authorization Requests with OAuth2 / Oidc - oauth-2.0

The specification of Pushed Authorization Requests says that request_uri should be single-use.
Since parts of the authorization request content, e.g., the code_challenge parameter value, are unique to a particular authorization request, the client MUST only use a request_uri value once. Authorization servers SHOULD treat request_uri values as one-time use but MAY allow for duplicate requests due to a user reloading/refreshing their user agent. An expired request_uri MUST be rejected as invalid.
So in typical flow:
Client receive request_uri from AS (Authorization Server)
Client redirects user to authorization endpoint with client_id and request_uri
User is at authorization page, all seems to work
But imagine that user refresh the page. Now the request_uri is used again so should be rejected. It cannot work like that.
So after the user is redirected to authorization endpoint we can set cookie with identifier that identifies request_uri. And later, if e.g. user refresh the page and request_uri is used again, we can assume the request is valid if contains appropriate identifier in cookie. If not, we can reject the request.
But now, they are not "really" single-use. Anybody who know identifier can use it.
What's more, not only refreshing page is problem. User can also be redirected to login or signup page. So what's the appropriate way to achieve request_uri one-time use with nice user exprience?

Related

Best way to store code_challenge and code_challenge_method in OAuth2(PKCE flow)

OAuth2(PKCE flow)
A client app makes a call to /authorize endpoint of the authorization server with code_challenge and code_challenge_method. Both code_challenge and code_challenge_method are required in the subsequent requests of the authorization server along with user credentials to generate the authorization code.
I can think of 2 options for how to store code_challenge and code_challenge_method to use in the subsequent calls:
persist the code_challenge and code_challenge_method before redirecting to the login page or user consent page
pass the code_challenge and code_challenge_method to the login page in query parameters, those then will be submitted along with the credentials
As RFC does not talk about this much, which option is better and why, or are there any other options? Please suggest.
Also, are there any best design practices about authorization server endpoints(except /authorize and /token) implementations in OAuth2(PKCE flow)?
According to Add Login Using the Authorization Code Flow with PKCE
There are 2 codes when doing PKCE :
Code verifier, the random string
Code challenger, the hashed string from the code verifier, and his hash method, the code_challenge_method
In the Oauth2 authorization_code flow, a client needs 2 tokens:
authorization token, to request accessToken
accessToken, to access resources
To get the authorization token with PKCE, a client app will have to pass the code challenger & method in the URL parameter, then the user is redirected to login page.
After login, the authorization server redirect user back to the client app, with authorization token in url parameters.
Finally the client app request access token with authorization token, code verifier, client id, and all other parameters.
When the ressources server receive the request for access token, it has to "remember" which code challenge to use to test with the code verifier.
Suppose there are 1000 users authorizing in the same time, there will be 1000 authorizations & code challengers per app client id.
The authorization server should accurately find the right user (authorization & code challenge) along the 1000 users to verify the code & generate access code.
I think this answers your question, storing code challenge after user login, which means pass it to login page (but encrypted, because there is a code challenge methode named plain...)
I don't see how we can link the user & code challenge when the authorization server first receive the authorization request.
RFC 7636 Section 4.4 states (emphasis mine):
Typically, the "code_challenge" and "code_challenge_method" values
are stored in encrypted form in the "code" itself but could
alternatively be stored on the server associated with the code. The
server MUST NOT include the "code_challenge" value in client requests
in a form that other entities can extract.
This rules out your option 2, as the challenge would be available in plain text to the user agent. It does however specify another option to encode this information into the code value, but it seems like this is not what you're looking for.
You're looking for a way to store the challenge while redirecting the user to the login page, before generating the code. In this case you could store the challenge in an encrypted httpOnly cookie in order to maintain a stateless design. A successful login would redirect the user agent back to your /authorize endpoint where you can extract the cookie again and generate the authorization response.

OAuth2 OIDC, How/When to give JWT to the browser?

I'm implementing a SSO solution. Got a general question regarding authorization code flow grant type as described here.
After a user login, the client app would get an ID token. But I cannot find anywhere how/when a JWT should be given to the browser such that it can set the bearer token in the request header for any subsequent request? Is it something not specified in the standard or I misunderstand something?
The browser does not set the Authorization request header automatically. You have to do it yourself using Javascript. This means that a request with such a header must be an AJAX call. If you want to send regular requests through the browser (by navigating to a URL), then you have to use cookies, as they will be automatically added by the browser. (You can keep the value of a token in a cookie and have your backend read a cookie instead of the Authorization header)

Who is reponsible for redirect in OAuth

How does the redirect in OAuth with IdentityServer4 work in detail? Calls the identity server the redirect URL directly (in case of loopback likely not possible) or does the browser get a response from Identity server with the redirect as parameter and the Browser does the redirect?
Is there a known issue that the response of the identity server can be changed to redirect to an other site? So can steal the authentication code.
IdentityServer4 redirects in the browser.
Yes, there is a known issue that response of identity server can be changed to redirect to an other site. There are also ways to mitigate those risks. You can use PKCE and nonce.
https://auth0.com/docs/flows/concepts/auth-code-pkce
https://developer.okta.com/blog/2019/08/22/okta-authjs-pkce
Rather than redirecting to another to a malicious endpoint (which will expose authorization code), higher probability is to have a Cross-site request forgery (CSRF) attack. For this OAuth 2.0 spec provide you with state parameter (more on this).
Regarding possibility of redirecting to a malicious endpoint, for this to be done,
Your original request must contain redirect url of malicious endpoit
Identity server must validate this url and then decide to perform the redirect
The second point is difficult to exploit (but possible). Because from OAuth 2.0 definition you register redirect URL when you register your client
The authorization server redirects the user-agent to the
client's redirection endpoint previously established with the
authorization server during the client registration process or when
making the authorization request.
So this means your identity server has been breached OR your registration was exploited. And you will have to worry about user being redirected to a malicious website, which could extract other important details rather than exposing authorization code.
This is emphasised in specification under Authorization Code Redirection URI Manipulation
An attacker can create an account at a legitimate client and initiate
the authorization flow. When the attacker's user-agent is sent to
the authorization server to grant access, the attacker grabs the
authorization URI provided by the legitimate client and replaces the
client's redirection URI with a URI under the control of the
attacker. The attacker then tricks the victim into following the
manipulated link to authorize access to the legitimate client.

Difference between OAuth 2.0 "state" and OpenID "nonce" parameter? Why state could not be reused?

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
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.
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.
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.
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.
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.
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.
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.

OAuth2: Why do we need redirect URI for user agent

I recently made a small app with webserver flow. Now I am trying user-agent example. I am wondering why do we need to define a redirect-uri in user agent flow.
I am working with Saleforce.com api:
http://wiki.developerforce.com/page/Digging_Deeper_into_OAuth_2.0_on_Force.com
redirect_uri The authorization server will respond with a redirect to this URI. This parameter must match your application's configured callback URL.
In a user agent flow, the redirect_uri is the location that the user gets redirected to after they click Approve on the approval page. Appended onto the redirect_uri are a hash fragment, and then the access_token, instance_url, and other oauth parameters.

Resources