After login page, the application makes multiple calls to bring up a report. Intermittently, some calls fail with 500 error with underlying message "A required anti-forgery token was not supplied or was invalid".
It doesn't always happen. Sometimes. the entire request is successful and the report comes up without issues. Other times, I see this anti-forgery error.
We have the same __RequestVerificationToken both failed and good calls in the same request. Session ID is the same as well. Any idea why it this issue is happening?
Successful request:
Failed request:
Problem
The CSRF token is being reused for requests subsequent to authentication A CSRF token is only valid for the initial session. Once authentication occurs, a new session is created and thus a new CSRF token is required.
TL;DR
You’re seeing an invalid token error because the token you’re using is from the session prior to user login
Solution
Refresh the CSRF token after authenticating user.
References
Refresh CSRF token after authentication: https://learn.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-3.1#refresh-tokens-after-authentication
Related
When the token is generated by sending a HTTP request to web API & the user has started working on the application that generated token is used in a particular session of the application. If during any HTTP request from the application to web API if JWT token expires WEB API won't return data. How is this situation handled in the application without any misbehavior or without troubling the user how that request will be continued?
And even if we generate a refresh token how to continue with the same HTTP request without troubling the user?
(If we store the generated token in the database then we know the token is valid but expired)
Try this :
Write backend refresh token API and allow an authenticated user to refresh their JWT token
In Frontend before requesting the API call decode the user's current JWT token and check whether it is expired or not.
https://www.npmjs.com/package/jwt-decode
If the token expired call the refresh token API before the actual request.
If you are using Angular or React library then there is a mechanism called HTTP_interceptor
https://www.bezkoder.com/angular-12-refresh-token/
https://www.bezkoder.com/react-refresh-token/
We also give a refresh token to the user along with the token, which has no claim and only has a username and a long expiration date. Every time the token expires, the security part of the applicationlooks at the refresh token and issues a new token for that username. You can manage the issuance of program tokens by setting the refresh token lifetime
I encountered this problem in test stage of my application. Client set expiration date of token for very long time (19 years or so), so we wouldn't request new token often during tests. But After a while it came out that token has already expired (after random time).
The problem was server application being restarted/updated, resulting in in-memory tokens lost and rendering my simple check for expires_in not working:
if (_currentToken.ExpirationDate < DateTime.Now.AddMinutes(1))
{
_currentToken = GetToken();
}
How would I secure such scenario? It might as well happen on production, but hopefully more rarely due to less application restarts and shorter token time. Unfortunately I don't have an access to server side authorization settings and tokens won't be persited in any storage.
I would like avoid calling some dummy action on server to check if it returns 401 unauthorized before every action.
IMO it's server side's responsibility to validate token and decide whether the request with token could access specific protected resources . So as #armagedescu suggested , just send the token when performing token request , server side will check the claims like expire time , issuer ... and also check the signature . If token is expired , it will return 401 status code , and the OAuth 2.0 bearer token spec adds error, error_description, and error_uri attributes to the WWW-Authenticate header for reporting additional error information :
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example",
error="invalid_token",
error_description="The access token expired"
Then on client side you can check the errors , and refresh access token to perform another token request .
I’m writing a web api that will be called from a background service to fetch some data. After some research I decided to use a Json web token to achieve that but I’m still a bit confused regarding when a new token should be requested.
Let’s say I start up my service, I request a token, the token expires after 15 minutes, then after 20 minutes I make an api call with the expired token. I will get an unauthorized error or something.
My question is: How will the client know when to request a new token? Should it request a new one before every api call? Seems like I’m missing something. Maybe I should make the token permanent and store it in the database?
Thanks
The answer to this is slightly application specific, but the OAuth specification has a mechanism for "refresh tokens", which can be used to grant new "access tokens" (the token typically included on each API request), without having to send the user to the UI authentication process to have them re-authenticate. So, once you request an access token, you will receive a refresh token and an access token. This methodology allows access tokens to be used for much shorter time frames.
This can also be done without refresh tokens, but in those cases the access token timeout would likely be longer, and then you would request that the user re-authenticate through the usual OAuth UI process. Note that even when you do have refresh tokens, the refresh token can also be set to expire, in which would then require a user re-authentication through UI again.
In some API's you just make the API request as usual, and if you get a response that is defined by the API to be one that indicates the access token has expired, you can then issue an API call to refresh the token (or fully request a new one if that is expired, or you the API doesn't have refresh tokens), and then make the original API call again with the new access token.
The API can also have a response that includes the timeout or expiration date/time of the access token as well. Then, the client can avoid sending the initial API call first, and simply send the refresh token call first.
In implementing your API, you could likely use any of these methodologies.
Here's some general discussion on the OAuth spec website, to provide more depth:
https://www.oauth.com/oauth2-servers/making-authenticated-requests/
https://www.oauth.com/oauth2-servers/access-tokens/access-token-lifetime/
https://www.oauth.com/oauth2-servers/access-tokens/refreshing-access-tokens/
And also, here's an example from the Twitter API regarding response codes showing one of the access token expiration techniques (see the "Error Codes" section, under error code 89, which implies the token has expired and you need to get a new one):
https://developer.twitter.com/en/docs/basics/response-codes
Since your client is background service , you can use the Oauth2 Client Credential Flow . Your background service can request an access token using only its client credentials when the client is requesting access to the protected resources under its control.
With this flow , you does't need to care much about the token expires , if client sends an expired token to web api , web api validate the token and create token expires response to your service , your service check the status code/response , directly send a new token request to web api to get new access token , there is no need to use refresh token which uses in other flows .
The fact is that your harness should be prepared to request any token when getting an Unauthorized status code. What I do in test is to check the expiration datetime, if close enough I refresh or get a new token whatever applies to your Auth. Also when getting an unauthorized status code my code does a refresh once and keep a count. If I get another unauthorized code then I return a false or throw an exception after I log the error on the second try. This works fine for me.
I've been trying to understand exactly how the antiforgery works. What confuses me are the cookies which are created. To my understanding, you include the antiforgery token in your form and then you validate for that token when a request is made. This way if a third party websites posts to your website, it will be denied.
Now, I'm reading here https://learn.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.1 that the antiforgery token gets stored in a cookie, maybe I'm reading this wrong? But why? Isn't the whole point of this not to make this value accessible outside of your website? If I look at my cookies, I can see 3 cookies created with antiforgery in their name.
services.AddAntiforgery(options =>
{
options.CookieDomain = "contoso.com";
options.CookieName = "X-CSRF-TOKEN-COOKIENAME";
options.CookiePath = "Path";
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.RequireSsl = false;
options.SuppressXFrameOptionsHeader = false;
});
I did a little test, I created a post form which ended up including anti forgery token and then I tried submitting it and it worked. Then I created another form without the token and then it failed. So to me it seems it only looks for the token passed in the form, then what is the cookie for?
Anti-forgery is a two-part process. When the page is generated, the token is included as part of the form, so that it will be posted along with the rest of your data. The cookie is set, for the client side of things. When the post is made, the client sends the request with the post data (including the token) and it sends the cookie back to the server, which also includes the token. Server-side, the posted token is matched up with the cookie token, and rejected if the two don't match.
This may seem weird since the client is posting both, but the cookie part ensures that the same client that got the page is also the same client sending it back. The goal isn't so much to protect the anti-forgery token, but rather to ensure that the page on your site is the one that's submitted, rather than some scammer's recreated version of your page. Since a third-party would be incapable of setting a cookie for your domain, there's no way they can fake this portion of the check, even if they were able to retrieve a valid token from your page by requesting it and parsing out the token.
From the asp.net core website AntiforgeryOptions.Cookie Property. The cookie part of the CSRF is only necessary when using cookie based authentication.
The cookie used by the antiforgery system is part of a security system that is necessary when using cookie-based authentication.
I have created a SAML library in my app that creates an authentication request and is successfully logged in, but when it sends a LogoutRequest, the response shows:
"samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"
This should mean that the session has ended successfully at the Idp correct? I provide the session ID and the username of the logged in user in the logout request the same way as successfully specified in the auth request. However, when I attempt another login request, I am not prompted for credentials as though the session is still active. What would cause this? I do not have access to the Idp's ADFS server to view the logs and they are taking a long time to respond with them. Could I be missing something and still get a success message when it really wasn't a successful logout?