Configure Cross-Side Request Forgery (CSRF) protection for SPAs

The goal of this section is to explain how any single-page application (SPA) can be protected from CSRF attacks by using the CSRF Token feature of the gateways Security Gate.

Configure the Microgateway to enable CSRF tokens using the corresponding csrf_token DSL settings. See DSL reference.

CSRF blocking based on CSRF tokens

Any state-changing request with a missing or invalid CSRF token will be blocked by the Security Gate. There are, however, legitimate use-cases for which the CSRF token is no longer valid. Typical examples are session timeouts or terminated sessions. In those cases, the gateway's response to a CSRF block might be inappropriate for a SPA.

  • Blocking responses:
  • If no Invalid token redirect location was configured, the response will be a 400 Bad Request with a generic HTML error page. SPAs typically do not expect HTML content in API responses.
  • Otherwise, the gateways response will be 303 See Other with a location header pointing towards the configured Invalid token redirect location. Redirects cannot be handled by SPAs based on XMLHttpRequest (XHR), such as Angular, and will be directly handled by the web browser.
  • The following steps are needed for the SPA to handle this situation more transparently:
  • Recognize that a CSRF block occurred.
  • Retrieve a new CSRF token.
  • Replay the original request with the new CSRF token.

Changing the gateway response for CSRF blocks

Set apps[].mappings[].csrf_token.invalid_token_redirect_location (see DSL reference) of the corresponding mapping to /%ENTRYPATH%/invalid/csrf-token.

Note that the exact path is not important as long as the configured value does not collide with any URL used in your application.

To ensure that the gateway's response can be handled by the SPA, we need to transform the redirect into for example a 403 Forbidden.

  - virtual_host: 
      name: <VH_NAME> 
      - name: <MAPPING> 
          apache: | 
            RewriteEngine On 
            RewriteRule "invalid/csrf-token" "-" [F]

The path given in the rewrite rule needs to match the previously configured invalid token redirect location. With this rewrite rule, any request to /%ENTRYPATH%/invalid/csrf-token will be responded to by a 403 Forbidden.

  • The changes above ensure that in case of a CSRF block:
  • The user's session ID and CSRF token will be renewed. These new values are delivered as cookies in the gateway's response (303 See Other towards /%ENTRYPATH%/invalid/csrf-token) to the CSRF block.
  • The user's browser follows the redirect and effectuates a GET /%ENTRYPATH%/invalid/csrf-token which is answered by a 403 Forbidden. This error is propagated to your SPA which can then handle it appropriately.

Intercepting in your SPA gateway response to CSRF Blocks

The exact syntax to intercept an HTTP request or response depends on the exact framework used by your SPA.

In the following example, we assume the SPA to use the Angular framework and will implement the HttpInterceptor interface. This was successfully tested with Angular 11 and 12.

Show moreShow less

Example of a CSRF Block Interceptor in Angular:

import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http'; 
import {Observable} from 'rxjs'; 
import {catchError} from 'rxjs/operators'; 
import {Injectable} from '@angular/core'; 
export class CsrfBlockInterceptor implements HttpInterceptor { 
    intercept (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { 
        return next.handle(req).pipe( 
            catchError((error: HttpErrorResponse) => { 
                if (this.isCsrfBlock(error)) { 
                    return this.replayRequest(req, next); 
                return this.anyOtherInternalErrorHandling(error); 
    private isCsrfBlock (error: HttpErrorResponse): boolean | undefined { 
        //the end of the url needs to match the one configured as "Invalid token redirect location" 
        return error.status === 403 && error.url?.endsWith('/invalid/csrf-token'); 
    private replayRequest (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { 
        return next.handle(req); 
    private anyOtherInternalErrorHandling (error: HttpErrorResponse) { 
        return observableThrowError(error); 

Sequences of requests and responses

Note that the normal sequence of requests and responses between your SPA and the Security Gate is not modified in any way by our exemplary configuration as long as no CSRF block occurs.

When a CSRF block occurs, then an extra round-trip between your application and the gateway is being made to handle the CSRF block transparently. This additional delay should be acceptable for most applications since a CSRF block typically occurs at most once per user session.

In case a CSRF block occurs, the sequence of requests and responses with our exemplary configuration is depicted below. Note that only relevant headers are displayed.

  1. (A) Your SPA does some state-changing requests (here a POST request) with an invalid CSRF token. This is for example the case when the user session is no longer valid (possibly due to a timeout).
  2. (B) The Security Gate verifies the provided CSRF token and considers it to be invalid since the corresponding session is invalid. This triggers a CSRF block.
    The gateway responds with a redirect towards the configured Invalid token redirect location and provides via cookies a new session ID and CSRF token.
  3. (C) The redirect is not propagated to your SPA but is instead directly handled by the user's web browser, which issues a GET request towards the configured invalid token redirect location.
  4. (D) The configured mapping settings ensure that any request towards the configured invalid token redirect location will be answered by 403 Forbidden.
  5. (E) The 403 Forbidden response is propagated to your SPA, which intercepts it and recognizes from the request URL in (C) that a CSRF block occurred.
    The SPA can then replay the original request from (A) transparently using the new session ID and CSRF token. The script initially injected by the Security Gate will automatically inject the CSRF token to the appropriate header.