Enhance Auth Endpoints To Support Sessions

Update your auth endpoints to properly manage user sessions.

Now that your Session Middleware is installed and configured to support cookie sessions, we need to update our authentication endpoints to manage the lifecycle of the user's session.


Update Existing Auth Endpoints

First, we'll need to update the existing Callback and Logout endpoints to create and clean up a user's session, respectively.


Update Callback Endpoint

After a user has successfully authenticated, Wristband will redirect to your application's Callback Endpoint. Calling the wristbandAuth.callback function will return a CallbackResult object containing the user's tokens and claims. We can use these tokens and claims to create the user's session by calling the req.session.save() function.

The below code example shows how to update your existing Callback Endpoint to create the user's session:

// 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;
    }
    
    /* ***** BEGIN NEW SESSION LOGIC ***** */

    // You can choose which user info to store in the session based on your app requirements.
    // The following fields are a good minimum to include.
    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.tenantDomainName = callbackData.tenantDomainName;
    req.session.tenantCustomDomain = callbackData.tenantCustomDomain || undefined;

    // This persists any updated session values.
    await req.session.save();
    
    /* ***** END NEW SESSION LOGIC ***** */

    return res.redirect(callbackData.returnUrl || '<replace_with_a_default_return_url>');
  } catch (err) {
    console.error(err);
    next(err);
  }
});

Update Logout Endpoint

When a user logs out of your application, you need to ensure that all authenticated state associated with the user is cleaned up. Therefore, we need to update our Logout Endpoint to invalidate the user's session and revoke their refresh token (assuming the session contains a refresh token).

The below code example shows how to update your existing Logout Endpoint to clean up the user's session:

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

  try {
    // NEW SESSION LOGIC: Pass the logoutConfig to the wristbandAuth.logout() method.
    return await wristbandAuth.logout(req, res, logoutConfig);
  } catch (err) {
    console.error(err);
    return next(err);
  }
};



Create a Session Endpoint

In addition to updating the Callback and Logout endpoints, we'll also need to create a Session Endpoint. The Session Endpoint will check that the incoming request has a valid session, and, if so, it will return a response containing the user's session data. The Session Endpoint serves two primary purposes:

  1. It provides a way for the frontend to check whether the user has a valid session.
  2. It allows the frontend to access the user's session data so it can be utilized in the browser.

Since this guide uses a React frontend, we'll structure the response to match what the React Client Auth SDK expects (which will be covered in the next section of this guide).

At a minimum, the response should include userId and tenantId.

// app.ts

...

// Session endpoint
app.get('/session', (req, res) => {
  const { isAuthenticated, userId, tenantId } = req.session;

  // Check that the user has an authenticated session.  If they don't, return a 401.
  if (!isAuthenticated) {
    return res.status(401).send();
  }
  
  //
  // If needed, you can make additional API calls to gather other session data you 
  // might want to return to your frontend.
  //

  // You can add any session data needed by the frontend to the response, but for 
  // now we'll add the bare minimum of the user's userId and tenantId.
  return res.status(200).json({ userId, tenantId });  
});

...

What’s Next

Now that session management is set up on the server, the next step is to integrate the sessions with the frontend.