What does this hospital mean with the following OAuth requirements? - oauth

We've got a hospital as a customer which wants to have an app developed. This app will probably make use of various ways of validation, of which OAuth2 is one. They have a list of requirements, of which one kind of puzzles me:
For every user session, the app needs to generate an unpredictable
"state parameter". The app needs to validate the "state value" for
every request which is sent to the redirect URL; the "state" needs to
be recorded with all authorization requests; and the "state value" has
to be validated with the access token which it receives.
Although they don't specifically mention it I guess this talks about OAuth. I've got some experience with OAuth2. I know what access tokens and refresh tokens are. But this story is above my head. What kind of "state parameter" and "state value" are they talking about?
Could anybody shed some light on this story?

This is about the state parameter that OAuth 2.0 has defined in the authorization request as a RECOMMENDED parameter (https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1) used to protected against cross-site request forgery and to correlate requests and responses in general:
state
RECOMMENDED. 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 as described in Section 10.12.

I believe they chose to write an OAuth 2.0 client application requirement on their own words. The specification states that:
The client MUST implement CSRF protection for its redirection URI. This is 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 used to authenticate the user-agent). The client SHOULD utilize the "state" request parameter to deliver this value to the authorization server when making an authorization request.
(emphasis mine, read the whole story in section 10.12 of the specification)
For a more step-by-step guided approach on how to use the state parameter you can refer to Using the State Parameter. This page mentions Auth0, but the process should be the same for any other OAuth 2.0 compliant server. Also note that the specific steps assume a browser-based application and as such store the unpredictable state parameter in Web storage. Other types of clients would use other stores, but the principle remains the same.

Related

Best practice on Securing code_verifier in PKCE-enhanced Authorization Code Flow

Since PKCE is now the recommended method of authorisation over the implicit flow, i'm looking for best practice on handling code verifier and recommendations on how this might be done. On high level PKCE Authorisation flow consist of:
Generate code_verifier on client side
Generate code_challenge from (1)
hit /authorise with code_challenge which redirect to select idp and in callback there's a code
use code from (3) along with code_verifier to exchange for access token
Question is, in step 3, before the application redirect to authorisation server and then the idp, one has to store the code_verifier somewhere. Where is that somewhere?
Seems like libraries like okta-oidc-js store the code_verifier in sessionStorage. Doesn't that expose you to XSS attack? i.e. if i was store the code_verifier in sessionStorage before the application goes into the Authorisation flow and redirects, on the callback, what stops some rouge extension from reading the code from the url and code_verifier from sessionStorage? Combination of which can be used to exchange for a access token.
What you describe is the standard SPA way of doing things - it could potentially be abused by malicious code, but there is some protection in the fact that an authorization code can only be used once and that the verifier is not stored for long.
A related XSS attack is to run a complete OAuth authorization redirect + code exchange on a hidden iframe - there is no protection against that, regardless of whether a back end or client secret is involved.
If you want to be strict about security, the emerging trend is more of a back end for front end approach, where the back end is a 'Proxy API' running at https://api.mywebdomain.com
The result of OAuth authorization is a same site cookie issued by the API, to prevent the above iframe attack
The SPA can then either use the auth cookie to get an access token or double hop API requests via the proxy API.
There is a good recent video on SPA security here that discusses these threats in further depth. The browser is a difficult place to implement security and redirects come with risks.
It is still recommended to separate Web and API concerns however - eg the above proxy API should not get in the way of a company wanting to deploy their SPA via a content delivery network.
LOGIN DANCE
In my opinion the preferred approach is summarized below, for full control and no issues with recent browser changes:
SPA calls a URL such as https://api.mywebdomain.com/login/start, which writes an HTTP only encrypted cookie for .mywebdomain.com containing the state and code_verifier, and also returns the authorization request URL
SPA then does the redirect itself, and saves page location / state to session storage beforehand if needed
SPA then receives the response URL with code and state, then POSTs them to a URL such as https://api.mywebdomain.com/login/end. Afterwards the SPA can restore its page location and state, so that usability is good.
API completes the login by verifying the state against that in the state cookie, then using the code_verifier from the state cookie. The result of all of this is to write an auth cookie (containing a refresh token) that could not be abused on an iframe.
I agree with Gary's approach, with one change.
The response url with code and state does not need to be intercepted by SPA and converted into another POST call to the BFF (backend for frontend).
If secure cookies were set on the browser at the beginning of the flow containing state and code verifier, the response url can land directly on the BFF which will then have all the parameters available for performing the code exchange (state and code as url parameters, code_verifier from cookie)

In OpenID Connect with PKCE, how does the client know which code_verifier to send with which authorization code after user redirect?

I'm taking a ASP.NET security course on OpenID Connect authorization code workflow with PKCE protection against code replay attack. There is one aspect of this process that I don't understand.
The process:
Relying client generates PKCE code_verifier, hash it into code_challenge, and send the user to the authorization server with the code_challenge as a query parameter.
The authorization server stores the code_challenge, issues authorization code, and redirects user back to client with the authorization code.
The client sends the authorization code along with the original code_verifier to exchange for tokens. The authorization server verifies that the code_verifier indeed hashes into code_challenge before issuing the token.
My question is step #3: since HTTP is stateless, how does the client know which code_verifier to send along with the authorization code? Is this code_verifier stored in a cookie on the user agent?
Using a cookie to store the "code verifier" appears to violate the spirit of the OpenId specification and just appears to be a big security hole.
In brief, the spec expects you to use S256 to hash the code verifier and the code verifier to be kept secret from eavesdropping or being guessed.
PKCE RFC Section 7.1 says the "The security model relies on the fact that the code verifier is not learned or guessed by the attacker. It is vitally important to adhere to this principle. As such, the code verifier has to be created in such a manner that it is cryptographically random and has high entropy that it is not practical for the attacker to guess."
... "The use of "S256" protects against disclosure of the "code_verifier" value to an attacker."
Now it does give an opening to using a cookie if you encrypt the "code verifier". Here is the what the spec says in
Section 7.2: "If the code challenge method is "plain" and the code challenge is to be returned inside authorization "code" to achieve a stateless server, it MUST be encrypted in such a manner that only the server can decrypt and extract it."
Well, OpenId specification has a solution and Microsoft has provided an implementation to follow. Refer to the "state" parameter in the OpenId specification when calling the "authorization" endpoint. The Identity Providers will return the value back to the caller.
The way it is done in .NET Core is using the "state" query string parameter whereby the value is a dictionary but protected (encrypted). For help look through the .NET core code and look at the method "BuildChallengeUrl" in "Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler"
Also, this Site has a great idea that works. It's a valid option.
PKCE was originally intended for mobile clients, which typically make only a single authorization request. But it is now recommended for all clients using the authorization code flow.
You're correct that if the client is a web application serving many users, the client application needs to associate the correct code_verifier with the authorization request.
As you say, the client could store the code_verifier in a cookie, so it will be sent to the client together with the authorization code.
Or it could store it server side on the client and stick the key in the state parameter to the authorization request. The state will be part of the call to the redirect_uri if passed along with the authorization request.

Should dynamic query parameters be present in the Redirection URI for an OAuth2 (Autorization Code Grant Type)

Sources such as this Okta sponsored site (see "Per-Request Customization" section) mention that the redirect_uri parameter of a autorization request SHOULD NEVER have a dynamic query part (ex: for session matching uses).
Quote:
The server should reject any authorization requests with redirect URLs
that are not an exact match of a registered URL.
Our OAuth AZ provider is BIG-IP F5. We are setting it up, and they seem to comply with the above view.
Our client is a web application built elsewhere, and they seem to not follow the above rule.
Here is a complete representation of the Authorization Endpoint (redacted):
https://ourownF5host.ca/f5-oauth2/v1/authorize?client_id=theIDofOurClient&redirect_uri=https%3A%2F%2FourClientAppHostname%2FClientRessource%2FRessource%3FSessionId%3D76eab448-52d1-4adb-8eba-e9ec1b9432a3&state=2HY-MLB0ST34wQUPCyHM-A&scope=RessourceData&response_type=code
They use a redirect_uri with a format similar to (I don't urlencode here, for simplicity's sake) : redirect_uri=https://ourClientAppHostname/ClientRessource/Ressource?SessionId=SOMELONGSESSIONID, with the SOMELONGSESSIONID value being DIFFERENT for each call.
We dug DEEP into RFC6749 (OAuth2), and found this in section 3.1.2.2:
The authorization server SHOULD require the client to provide the
complete redirection URI (the client MAY use the "state" request
parameter to achieve per-request customization). If requiring the
registration of the complete redirection URI is not possible, the
authorization server SHOULD require the registration of the URI
scheme, authority, and path (allowing the client to dynamically vary
only the query component of the redirection URI when requesting
authorization).
What I understand, and would like to validate here, is that the first source, Okta and F5 accept ONLY the first part of the rule above, and require the redirection uri to be COMPLETELY registered without any dynamic part.
Am I right to affirm that they (Okta and F5) DO NOT comply with the second part of the excerpt, citing that they should "allow(ing) the client to dynamically vary
only the query component of the redirection URI when requesting
authorization" ?
OR, is there any kind of official correction/evolution of the RFC6749, that warrants both companies design position ?
TL;DR:
No, the redirect uri must be static for security reasons. If the client needs to keep a state between the authorization request and its asynchronous response, use the OAuth 2.0 state parameter.
Long version :
RFC6749 (the initial OAuth 2.0 specification) has been published in 2012 and OAuth security landscape has evolved a lot since then.
RFC6819, an OAuth 2.0 security review from 2013 already mentioned that refusing dynamically crafted redirect uris was a good way to protect against XSS and client impersonation attacks.
OpenID Connect, from 2014, a commonly used extension of OAuth 2.0 with authentication capabilities, already takes that recommendation into account and mandates exact string matching for all redirect uris.
The current draft recommendation for OAuth 2.0 Best Security Practice confirms that by enforcing redirect_uris preregistration and mandating the use simple string comparison by the AS when validating the redirect_uri passed in the request. So a dynamic redirect_uri must not be used.
Your client definitely makes a wrong move by using the redirect_uri as a "state keeper" between the Authorization request and response, by using a dynamically crafted SessionID attribute inside the redirect_uri. OAuth2.0 has a dedicated authorization request parameter for that purpose, which is "state". The client should use it. The AS will append that state in the parameters of the redirect_uri when it issues the response, so the client will be able to find back this state inside the response.
The proper authorization request would be:
https://youras/authorize?client_id=your_client_id&response_type=code&state=SOMELONGSTATE&redirect_uri=https%3A%2F%2Fsomehost%2Fauthcallback
The response will look like:
https://somehost/authcallback?state=SOMELONGSTATE&code=anazcode
This way the redirect_uri is static, so a simple string comparison is enough to validate that uri on AS side. Any algorithm more complex than simple string comparison would be subject to security flaws.
It appears there's two things mixed up here: the URL you refer to:
https://somehost/authcallback?state=SOMELONGSTATE&scope=someobjecttype&response_type=code
suggests that you mixed up the Redirect URI (aka. callback URL, as suggested by the pathname in the URL) of the Client with the Authorization Endpoint of the Authorization Server.
Only the Authorization Endpoint would take parameters as suggested and may contain e.g. a dynamic state value. The Redirect URI of the Client would not contain e.g. response type.
A redirect_uri parameter can be added to the the authorization request, which would then have to be matched in the way that you described. After confirming the match, the Authorization Server will redirect back to the Redirect URI, adding the code and state parameters.
Update (after the question changed):
OAuth 2.0 RFC6749 allows a dynamic (SessionId) parameter though it is not considered best practice. If however your client is an OpenID Connect Client, this is not allowed since the OpenID Connect spec (a "profile" of OAuth 2.0) locks down the Redirect URI matching to "exact", in which case you'd have to configure all possible SessionIds.

Why do I need to follow the OAuth spec/guidelines?

I feel silly even asking this question, but am at the limits of my understanding, and am hoping someone can provide some context.
I'm looking at the following (https://stormpath.com/blog/token-auth-for-java/) which states:
The access_token is what will be used by the browser in subsequent requests... The Authorization header is a standard header. No custom headers are required to use OAuth2. Rather than the type being Basic, in this case the type is Bearer. The access token is included directly after the Bearer keyword.
I'm in the process of building a website, for which I'll be coding both the back-end REST service, as well as the front-end browser client. Given this context, why do I need to follow any of the guidelines given above? Instead of using the access_token, Authorization and Bearer keywords, what's stopping me from using any keywords I like, or skipping the Bearer keyword entirely in the header? After all, as long as the front-end and back-end services both read/write the data in a consistent manner, shouldn't everything work fine?
Are the keywords and guidelines given above merely best-practice suggestions, to help others better understand your code/service? Are they analogous to coding-styles? Or is there any functional impact in not following the above guidelines?
Given this context, why do I need to follow any of the guidelines given above?
Because they are standardized specifications that everyone is meant to conform to if they want to interact with each other.
Instead of using the access_token, Authorization and Bearer keywords, what's stopping me from using any keywords I like, or skipping the Bearer keyword entirely in the header?
Nothing, except that it won't be OAuth anymore. It will be something custom that you created for yourself that noone else will understand how to use, unless you publish your own spec for it.
After all, as long as the front-end and back-end services both read/write the data in a consistent manner, shouldn't everything work fine?
Who is to say that you alone will ever write the only front-end? Or that the back-end will never move to another platform? Don't limit yourself to making something custom when there are open standards for this kind of stuff.
Are the keywords and guidelines given above merely best-practice suggestions, to help others better understand your code/service?
No. They are required protocol elements that help the client and server talk to each other in a standardized manner.
Authorization is a standard HTTP header used for authentication. It has a type so the client can specify what kind of authentication scheme it is using (Basic vs NTLM vs Bearer, etc). It is important for the client to specify the correct scheme being used, and for the server to handle only the schemes it recognizes.
Bearer is the type of authentication that OAuth uses in the Authorization header. access_token is a parameter of OAuth's Bearer authentication.
If you use the Authorization header (which you should), you must specify a type, as required by RFCs 2616 and 2617:
Authorization = "Authorization" ":" credentials
credentials = auth-scheme #auth-param
auth-scheme = token
auth-param = token "=" ( token | quoted-string )
So, in this case, Bearer is the auth-scheme and access_token is an auth-param.
Are they analogous to coding-styles?
No.
Or is there any functional impact in not following the above guidelines?
Yes. A client using your custom authentication system will not be able to authenticate on any server that follows the established specifications. Your server will not be able to authenticate any client that does not use your custom authentication system.

How to identify provider for oauth2 redirect_uri callback?

Im trying to undertand how to properly identify which provider a returning authorization request was initiated by. I see three approaches:
Use provider specific redirect_uri callback URIs. /oauth2/<provider-name>/callback etc.
Encode provider id/name in state parameter somehow
Store a pending provider id/name in the web session
Try to verify response with all used providers
I've read parts of the OAuth2 spec but I can't find anything discussing it. Looking at other client implementations it seems as provider specific URIs is the most common solution. Am I missing something?
Clients may not be multi-tenant and are tightly integrated with a single Authorization Server, so there's no need to store a provider identifier because there's only a single fixed one. That may be the reason why there's no obvious solution.
Multi-provider clients like your's should store the provider identifier as part of the state. This is because the state should be protected, and the provider specific redirect_uri is not. One could play an access token for provider A against the callback for provider B and thus defeat the purpose of a provider specific callback.
state can be protected either by reference to server state or to an encrypted cookie, or by value in the form of a self-contained encrypted structured value for the state parameter, and thus can be a safe mechanism to store the provide identifier.

Resources