My application consists of a client side html/javascript, a web server, and an API (a "regular web app", as auth0 calls it). On the Authorization Code Grant doc page on Auth0, it says to create a URL like this:
https://ygctest.auth0.com/authorize?
audience=YOUR_API_AUDIENCE&
scope=YOUR_SCOPE&
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=https://YOUR_APP/callback&
state=YOUR_OPAQUE_VALUE
The doc says the state (apparently a nonce to prevent CSRF) returned from the auth0 server via query parameter to /callback needs to be compared to the originally generated state.
My question is: Where should the "state" variable be generated? And, does the state variable need to be verified on the client, server, or both?
Should I generate it on the server and pass it to the client somehow? If so, is it better to do it as a cookie, or can I just generate the entire URL serverside and stick it in the html?
If the state variable should be generated on the client side, how should the server know what the client thinks the state is? The browser is redirected from the login page to /callback (in the example), so the client doesn't have a chance to check the state. Should the client set a cookie so that the GET to /callback includes the state?
Create the session state on the server-side, store its value in session (encrypted cookie or server-side storage cache (eg. Redis). Then during the code authorization grant flow, check its value as a first action in your callback. Some libraries might handle the check for you, or else you will have to do the ceremony of pulling the state value explicitly out of session storage in your code, and comparing that explicitly against the value of state that was returned to your callback endpoint.
If you are using Auth0 Hosted Login Page, and making a call to authorize endpoint, then you can just do it all server-side - see here. If you need to render a form on UI with state value then your Controller can pass the value of your state to the view layer as a value that gets interpolated. The key takeaway is that it is recommended to generate the value server-side, store it in secured session storage, and do the comparison server-side (in the callback) for code authorization grant flow (regular web app).
Related
I'm trying to understand the difference between code_challange and state parameter from OAuth 2.0 Authorization Code Flow + PKCE.
I know that state parameter is a validation against CSRF attack and is generated (and saved in local storage) on Client (eg. Angular SPA) - and need to be returned from Authorization application in callback after successful login and compared with state value saved previously on local storage.
Whereas code_challange is generated based on code_verifier also genereated and saved in localstorage. So where is the differance with usage?
Also I've noted strange thing - I copied generated auth url which is: https://APP_ADDRESS.b2clogin.com/APP_ADDRESS.onmicrosoft.com/b2c_signupsignin/oauth2/v2.0/authorize?client_id=f9d2b[...]&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fauth-callback&response_type=code&scope=f9d2b[...]%20openid&state=31caa207[...]&code_challenge=-MefGRhOo[...]&code_challenge_method=S256&response_mode=query
And I used that url in different browser. And I was able to login successfuly. I only had an error in console: No matching state found in storage. Which make sense since local storage was empty in new browser.
But why there wasn't any error about the code_challange? I think it shouldn't be able to login successful, or I miss something?
With PKCE, the checks that the code_challenge is correct is done on the authentication server-side and the check for valid state is done on the client-side.
There are cases where the client does not check the state/nonce properly (or not at all) and we added PKCE to let the auth-server do the check instead. The auth server can force/require that all clients follow the PKCE concept.
Together we get a very strong protection.
The picture below shows how PKCE works
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)
I have created an authentication server that implements OAuth 2 for authorization and it also provides local password authentication using the resource owner flow.
At the moment I always return a refresh token along with the access token which was an acceptable thing to do when I first implemented the feature. However now I need to implement a remember me feature in the client that uses the server. I could always just save the refresh token in the client when the user ticks the remember me checkbox but the token would still exist on the server and be usable even though the user didn't want it to.
What I want to do is simply pass a parameter along with the request that tells me whether I should create a refresh token or not.
So my question is. Is there some standard or recommended way of doing this using the fields provided in the spec or is it acceptable to simply add a parameter to the request to handle this use case?
AFAIK, there is no standardized way to choose whether to issue a refresh token or not.
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.
I've Google'd, but haven't been able to determine if ASP.NET MVC's v4 RequestVerificationToken should be different for every request?
I notice this in all environments, even when running on a single server. The user is logged in, but when refreshing the page (F5) a different token is generated every time.
Is this normal or not?
This is completely Normal. No difference when a user is logged in or not.
Note that: Synchronizer token pattern is a technique where a token, secret and unique for each request, is embedded by the web application in all HTML forms and verified on the server side. The token may be generated by any method that ensures unpredictability and uniqueness (e.g. using a hash chain of random seed). The attacker is thus unable to place a correct token in his requests to authenticate them