In angular documentation, it is mentioned that the angular httpclient
will automatically send the value of cookie XSRF-TOKEN
in the header X-XSRF-TOKEN
of post request. Documentation link
But it does not send the header for me. Here is my code
Nodejs code to set the cookie
router.get('/set-csrf',function(req,res,next){ res.setHeader('Set-Cookie', "XSRF-TOKEN=abc;Path=/; HttpOnly; SameSite=Strict"); res.send(); })
I have used the httpclient in app.module.ts
imports: [ HttpClientModule ]
** The above code is just for debug purpose. I do not have a set-csrf endpoint.
But it does not send any header when I send a post request. I am not able to debug.
I have added the issue in the github repository of angular too. HttpXsrfInterceptor checks if the request is GET or HEAD, or if it starts with http. If true, it skips adding the header.
Here is the code in HttpXsrfInterceptor class
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const lcUrl = req.url.toLowerCase(); // Skip both non-mutating requests and absolute URLs. // Non-mutating requests don't require a token, and absolute URLs require special handling // anyway as the cookie set // on our origin is not the same as the token expected by another origin. if (req.method === 'GET' || req.method === 'HEAD' || lcUrl.startsWith('http://') || lcUrl.startsWith('https://')) { return next.handle(req); } const token = this.tokenService.getToken(); // Be careful not to overwrite an existing header of the same name. if (token !== null && !req.headers.has(this.headerName)) { req = req.clone({headers: req.headers.set(this.headerName, token)}); } return next.handle(req); }
I am not sure why they have skipped for http/s part. Here is my issue in github
It is added to the request header for ajax requests. Popular libraries like angular and axios , automatically get value of this header from xsrf-token cookie and put it in every request header.
The XSRF-TOKEN cookie is both httponly and secure, it is getting decrypted accurately and it does match up with the token stored for the session on the server.
The client acquires a new CSRF token from the server by calling the REST endpoint baseURL/v1/csrf/tokens. The server generates a new, unique CSRF token and sends the token to the client in a custom HTTP response header.
CSRF token was designed for server rendering... not SPA. In SPA you already use token during authentication, so no need to use another token for CSRF. CSRF was designed as a protection for cross site calls, but API itself designed in a way that it allows request from anywhere until, they are authenticated.
What you are looking for is HttpClientXsrfModule
.
Please read more about it here: https://angular.io/api/common/http/HttpClientXsrfModule.
Your usage should be like this:
imports: [ HttpClientModule, HttpClientXsrfModule.withOptions({ cookieName: 'My-Xsrf-Cookie', // this is optional headerName: 'My-Xsrf-Header' // this is optional }) ]
Additionally, if your code targets API via absolute URL, default CSRF interceptor will not work out of the box. Instead you have to implement your own interceptor which does not ignore absolute routes.
@Injectable() export class HttpXsrfInterceptor implements HttpInterceptor { constructor(private tokenExtractor: HttpXsrfTokenExtractor) { } intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const headerName = 'X-XSRF-TOKEN'; let token = this.tokenExtractor.getToken() as string; if (token !== null && !req.headers.has(headerName)) { req = req.clone({ headers: req.headers.set(headerName, token) }); } return next.handle(req); } }
And finally add it to your providers:
providers: [ { provide: HTTP_INTERCEPTORS, useClass: HttpXsrfInterceptor, multi: true } ]
I suppose the correct method is withOptions
. I used withConfig and got error Property 'withConfig' does not exist on type 'typeof HttpClientXsrfModule'.
This is a typing issue in the documentation. You need to use "withOptions" instead HttpClientXsrfModule.withOptions({ cookieName: 'My-Xsrf-Cookie', headerName: 'My-Xsrf-Header', })
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With