HTML AntiForgery Token not working with Angular 5 SPA - asp.net-web-api

I have an Asp.Net MVC 5 with Angular 5 SPA.
In my index.cshtml page I've added
#Html.AntiForgeryToken()
this creates hidden token value and a cookie.
Now, I read the hidden token value and attach it to the headers for post call using Angular interceptor.
In my Web API controller, I do get the token and cookie values correctly.
However, the statement,
AntiForgery.Validate(tokenCookie, tokenHeader);
throws invalid token error.
NOTE: cookie value is same through out the session. But hidden token value changes when I navigate. Not sure about how this is happening in a SPA.
Let me know if any idea on this.

Related

CSRF Token keeps refreshing every 2nd request. (Spring boot 3 and Next.JS)

I've been creating a Spring boot 3 and Next.JS app with Spring Security. Been having some problems with the "Set-Cookie" header being refreshed on every 2nd request I make to the backend. I can illustrate the problem as:
Make a request to /finances (with XSRF-TOKEN provided post-successful login)
The request goes through (contains all the necessary data for a valid request [CSRF cookie, JWT token, etc..]). The response contains a "Set-Cookie: XSRF-TOKEN= ...." header without the TOKEN.
I refresh the page (make a new request using the useEffect hook) and the CSRF cookie appears again, a new one.
If i refresh the page (make a new request using the useEffect hook) again, the CSRF cookie is deleted.
And so on.
I pass the cookie value on every request to the backend (whenever it is available) and the backend operates on it correctly. So there are no problems with the token validation.
I've also read that the spring security will provide a new XSRF cookie/value if the request from the client does not provide a cookie of the same name.
Could some one please help?
I've tried configuring the response on the backend to attach a new cookie with the same value, and also saving the cookie value in the session storage for later use. None of the options seem to work.
Making two requests to the server would solve the issue (probably) but that would not be an optimal solution. To the problem.

Laravel Vue JS JWT Implementation

I am trying to understand how an auth in a spa context with a jwt token should be implemented based on a Register / Login / Logout process. I have been searching on the web and have implemented at laravel side tymon jwt but I am confused about next step regarding register form and login form.
Do I understand well that when my user register for the first time on my website, this is at this time that the JWT token should be generated and recorded in a cookie ? If yes, is it Vue or Laravel which should record the JWT token in a cookie ? I suppose Vue ?! If yes, in which manner?
Other question: what happen if the user clear the browser cache and eliminate the cookie containing the JWT form his computer ? Does he need to register again to get a a new token ?? I am totally confused about the process.
Getting a more detailed and step by step process would help.
Thanks
The rough sketch for a JWT authentication works like this:
Registration - (optional | If the user is not registered) User fills the registration form which is posted to the register route, User account is created and the api responds with 201 ( content created)
Login - User uses his credentials to login to the app. The credentials are verified and a JWT token is issued and sent back to the user.
Vue handles the JWT Token and stores the provided token into cookies ( you can use js-cookie to handle this, usually in Vuex state )
The token is used with every request sent forth to the server, server verifies the Token and then the request proceeds.
Logging out requests the server to invalidate the token and then removes the token from the cookies.
You can use laravel passport, Laravel Sanctum or tymon/Jwt for token management.

CSRF token value when same page is opened in two tabs on same machine?

From my understanding, when CSRF is enabled on server side, the server creates a token (say token1) and injects it in to the form and saves the same in the cookie of the client browser.
When the client sends the form request to the server, it sends the csrf token (token1) from browser cookie and also send the same token as in the form. The server validates the request by checking that the token in cookie and the token in form match and then processes the request.
Now, if i open the same form in another tab, will the server generate another token (token2) and inject it in to the form and cookie. Then, in the cookie, token1 will be overwritten by token2. So the submission of the form in first tab will not work in this case? But from experience i see that the submission of form in tab 1 still succeeds.
So can some one explain how it's succeeding in the above scenario??
Since you have added the Spring Security tag, I will describe how Spring Security uses the Synchronizer Token Pattern to protect against CSRF attacks.
the server creates a token (say token1) and injects it in to the form and saves the same in the cookie of the client browser.
That's not exactly what happens. The server will create a CSRF token (token1) and store that token in the HttpSession. The CSRF token (token1) is also be embedded in the form on the client side. The client is also given a Session ID (session-id1) which is stored in a cookie.
When the client submits the form, it sends token1 and session-id1. The server will then use session-id1 to look up the HttpSession and get the expected CSRF token for that session. It will compare the expected CSRF token to token1 and if the values do not match, the HTTP request will be rejected.
If you open the same form in another tab, the browser will still have access to the Session ID (session-id1). That form will get the same token (token1) that was associated with session-id1.
In the end, there is only one CSRF token (token1) that is used in both tabs.
You can find more information about protection against CSRF attacks in the Spring Security reference documentation.

CSRF token expiration with flask and wtform

What is the best practice when it comes to CSRF token expiration?
Say a user is visiting a page (Jinja template) with a form, but tries to submit says form only n hours later. The CSRF token is obviously expired by then.
Of course I could stretch the token's lifespan, but I'm looking for a better way to do this.
Should I try and fetch a new token through an ajax request, before submitting the form with ajax?

419 error in second login after a logout in a SPA using Laravel API and Vue.js

I'm getting a page expired error (er.419) when I try to login after a previous logout.
I'm working on auth pages for SPA made with Laravel and Vue.js. It works well on first login but after a logout it shows an error submitting the second one login.
I think the issue is the CSRF sent previously and (maybe) expired after logout.
My work flow is this:
login component has hidden form sent as POST method to Laravel API having the csfr-token value from an HTML META TAG set up when app is created by Laravel template:
meta name="login-status" content="{{ Auth::check() }}"
The logout is done by a fetch request in a vue component. So no refresh is done.
Thanks for any suggestion!
From the laravel docs (https://laravel.com/docs/5.8/csrf#csrf-introduction):
Laravel automatically generates a CSRF "token" for each active user session managed by the application. This token is used to verify that the authenticated user is the one actually making the requests to the application.
When you logout, you are invalidating your current session - which means that the csrf token you have cached in your meta becomes invalid.
Solution 1
Refresh the page when you successfully logout, so php can output the active csrf token into your meta tag. For example:
fetch('/api/logout', {
method: 'post'
}).then(() => {
window.location.href = '/login';
});
Solution 2
Consider using the api route middleware group. Doing so will mean the application will not trigger the App\Http\Middleware\VerifyCsrfToken middleware. Bear in mind though that you will no longer have access to the session, so you'll need to look into stateless authentication techniques such as via JWT's.
Laravel themselves even provide a package for authenticating api's. (https://laravel.com/docs/5.8/passport)

Resources