Enhance Auth Routes with CSRF

Store and clear CSRF secrets in your application sessions.

Your Express server maintains each user's CSRF secret in their application session, which is used for cryptographically signing any generated CSRF tokens.

Now that your CSRF middleware is installed, add CSRF management logic into your auth routes.


Callback Endpoint

Your Callback endpoint should persist a CSRF secret into the session and set the CSRF cookie in the response so that all subsequent requests can properly validate CSRF state.

// Callback endpoint
app.get('/auth/callback', async (req, res, next) => {
  try {
    const callbackResult = await wristbandAuth.callback(req, res);
    const { callbackData, result } = callbackResult;

    if (result === CallbackResultType.REDIRECT_REQUIRED) {
      return;
    }

    req.session.isAuthenticated = true;
    req.session.accessToken = callbackData.accessToken;
    // Convert expiration seconds to a Unix timestamp in milliseconds.
    req.session.expiresAt = Date.now() + callbackData.expiresIn * 1000;
    req.session.refreshToken = callbackData.refreshToken;
    req.session.userId = callbackData.userinfo.sub;
    req.session.tenantId = callbackData.userinfo.tnt_id;
    req.session.identityProviderName = callbackData.userinfo.idp_name;
    req.session.tenantDomainName = callbackData.tenantDomainName;
    req.session.tenantCustomDomain = callbackData.tenantCustomDomain || undefined;
    
    /* ***** BEGIN NEW CSRF LOGIC ***** */
    
    req.session.csrfSecret = createCsrfSecret();
    await req.session.save();
    updateCsrfTokenAndCookie(req, res);
    
    /* ***** END NEW CSRF LOGIC ***** */

    return res.redirect(callbackData.returnUrl || 'http://localhost:3000/your-react-home-route');
  } catch (err) {
    console.error(err);
    next(err);
  }
});



Logout Endpoint

The Logout endpoint should destroy the CSRF cookie before redirecting to the Wristband Logout endpoint.

// Logout endpoint
app.get('/auth/logout', async (req, res, next) => {
  const { refreshToken, tenantCustomDomain, tenantDomainName } = req.session;
  const logoutConfig = { refreshToken, tenantCustomDomain, tenantDomainName };
  res.clearCookie(SESSION_COOKIE_NAME);
  
  /* ***** BEGIN NEW SESSION LOGIC ***** */
  
  res.clearCookie(CSRF_TOKEN_COOKIE_NAME);
  
  /* ***** END NEW SESSION LOGIC ***** */
  
  session.destroy();

  try {
    // Make sure to include refresh token and tenant domain in logout config for
    // successful revocation and redirection.
    return await wristbandAuth.logout(req, res, logoutConfig);
  } catch (err) {
    console.error(err);
    return next(err);
  }
};

Lastly, let's enhance the React frontend to be able to pass custom CSRF request headers to Express.