Logout

Learn how Wristband SDKs log users out and revoke refresh tokens.

The Logout Endpoint is where users go to log out of your application. Your frontend redirects users to it when they log out. For example:

GET https://customer01.yourapp.io/auth/logout

Logging a user out fully involves three things:

  • Destroying your application session: Handled by your Logout Endpoint.
  • Revoking the user's refresh token: Handled by the SDK's logout function.
  • Ending the user's Wristband auth session: Handled by redirecting the user to the Wristband Logout Endpoint. The SDK's logout function builds this redirect, and your Logout Endpoint returns it.

For example, using the Express Auth SDK:

app.get('/auth/logout', async (req, res) => {
  const { refreshToken, tenantCustomDomain, tenantName } = req.session;
 
  // Always destroy your application's session.
  req.session.destroy();
 
  const logoutUrl = await wristbandAuth.logout(req, res, {
    refreshToken,
    tenantCustomDomain,
    tenantName
  });
  res.redirect(logoutUrl);
});

The logout function also accepts an optional logout configuration, which provides the refresh token and the user's tenant, along with other options covered in the sections below.

Destroying the Session

Your Logout Endpoint destroys the application session by calling the session's destroy() function, as shown in the example at the top of this page. Destroying the session clears its data, so read the values the logout function needs, such as the refresh token and the user's tenant, from the session first. Some SDKs instead destroy the session onto the response your Logout Endpoint returns, using destroyToResponse().

Refresh Token Revocation

If your application requested the offline_access scope during login, it receives a refresh token. That refresh token stays valid after the user logs out unless it’s revoked, and could still be used to get new access tokens. When you pass the user's refreshToken in the logout configuration, the SDK revokes it by calling the Wristband Revoke Token Endpoint.

If the revoke request fails with a server error or a network failure, the SDK retries it, up to three attempts in total, waiting 100 milliseconds before the first retry and doubling the wait after each one. Client errors (4xx) aren't retried. If revocation still fails, the SDK doesn't block the logout. It continues building the redirect to the Wristband Logout Endpoint.

Tenant Resolution

The Wristband Logout Endpoint ends the user’s auth session for a specific tenant, so the SDK first tries to resolve the user’s tenant at your Logout Endpoint, which determines the domain it uses when building the Wristband Logout URL. It checks the following sources in precedence order, where each one resolves to a Tenant-Level domain:

  1. tenantCustomDomain logout configuration: The tenant custom domain of the user's tenant, typically read from the application session.
  2. tenantName logout configuration: The name of the user's tenant, typically read from the application session.
  3. tenant_custom_domain query parameter: A tenant custom domain passed to your Logout Endpoint (e.g. https://yourapp.io/auth/logout?tenant_custom_domain=mytenant.com). The SDK first validates it with the Wristband Validate Custom Domain API, and if it isn't a valid tenant custom domain for your application, the SDK ignores it and moves on to the next source.
  4. Tenant subdomain: The tenant name in the request's host, when your loginUrl contains the {tenant_name} placeholder (e.g. https://customer01.yourapp.io/auth/logout). If your application runs behind a reverse proxy, see the Reverse Proxies section of Backend SDK Configuration for how the SDK determines the host.
  5. tenant_name query parameter: A tenant name passed to your Logout Endpoint, when your loginUrl doesn't contain the placeholder (e.g. https://yourapp.io/auth/logout?tenant_name=customer01).

If your application uses tenant subdomains, the SDK parses the tenant from the request's subdomain, so you don't need to pass tenantName in the logout configuration. If your application has a mix of tenants that use tenant subdomains and tenant custom domains, pass both the tenant name and the tenant custom domain, either in the logout configuration or as query parameters, so the SDK can handle every tenant type.

For example, using the Express Auth SDK with the tenant passed through the logout configuration:

const { refreshToken, tenantCustomDomain, tenantName } = req.session;
 
const logoutUrl = await wristbandAuth.logout(req, res, { refreshToken, tenantCustomDomain, tenantName });
res.redirect(logoutUrl);

Or with the tenant passed by your frontend through query parameters, such as https://yourapp.io/auth/logout?tenant_custom_domain=mytenant.com&tenant_name=customer01:

const { refreshToken } = req.session;
 
const logoutUrl = await wristbandAuth.logout(req, res, { refreshToken });
res.redirect(logoutUrl);

When No Tenant Is Resolved

If none of these resolve a Tenant-Level domain, the SDK can't send the user to the Wristband Logout Endpoint. Instead:

  • If redirectUrl is set in the logout configuration: The SDK returns that URL directly.
  • Otherwise, when applicationAuthorizationRequestsEnabled is true: The SDK returns your Login Endpoint URL, with the {tenant_name} subdomain removed if your loginUrl contains the placeholder (e.g. https://yourapp.io/auth/login), so a new Application-level login can start.
  • Otherwise, when applicationAuthorizationRequestsEnabled is false: The SDK returns the Application-Level Login (Tenant Discovery) Page URL, either the Wristband-hosted page (e.g. https://yourapp-yourcompany.us.wristband.dev/login?client_id=123) or your self-hosted page if customApplicationLoginPageUrl is set.

Return Value

The logout function returns where your Logout Endpoint should redirect the user. Depending on how the SDK resolved the tenant, that destination is one of the following:

  • The Wristband Logout Endpoint on a Tenant-Level domain: When the SDK resolved a tenant.
  • The redirectUrl from the logout configuration: When no tenant was resolved and redirectUrl is set.
  • Your Login Endpoint without tenant information: When no tenant was resolved, redirectUrl isn't set, and applicationAuthorizationRequestsEnabled is true.
  • The Application-Level Login (Tenant Discovery) Page: When no tenant was resolved, redirectUrl isn't set, and applicationAuthorizationRequestsEnabled is false. This is either the Wristband-hosted page or your self-hosted page if customApplicationLoginPageUrl is set.

How the destination is returned depends on the SDK:

  • As a URL: Some SDKs return the URL as a string, and your Logout Endpoint performs the redirect itself. For example, using the Express Auth SDK, which returns a URL:
    app.get('/auth/logout', async (req, res) => {
      const { refreshToken, tenantCustomDomain, tenantName } = req.session;
     
      // Always destroy your application's session.
      req.session.destroy();
     
      const logoutUrl = await wristbandAuth.logout(req, res, {
        refreshToken,
        tenantCustomDomain,
        tenantName
      });
      res.redirect(logoutUrl);
    });
  • As a redirect response: Some SDKs return a ready-made redirect response, and your Logout Endpoint destroys the session onto it and returns it. For example, using the Next.js Auth SDK with the App Router, which returns a redirect response:
    export async function GET(req: NextRequest) {
      const session = await getRequestSession(req);
      const { refreshToken, tenantCustomDomain, tenantName } = session;
     
      const logoutResponse = await wristbandAuth.appRouter.logout(req, {
        refreshToken,
        tenantCustomDomain,
        tenantName
      });
     
      // Always destroy your application's session.
      return await session.destroyToResponse(logoutResponse);
    }
🚧

Responses Must Not Be Cached

The SDK sets the Cache-Control: no-store and Pragma: no-cache headers on every response from your Logout Endpoint. If a browser or intermediary cache reused a logout redirect, a later logout could skip your Logout Endpoint entirely, leaving the application session in place and the refresh token unrevoked.

Logout URL Parameters

When the destination is the Wristband Logout Endpoint, the SDK builds the URL on the tenant's domain. For a tenant name, the domain format depends on isApplicationCustomDomainActive, the same as for login (see the Application-Level Custom Domain section of Backend SDK Configuration).

For example:

https://customer01-yourapp-yourcompany.us.wristband.dev/api/v1/logout?client_id=123

The URL includes the following query parameters:

Query ParameterValue
client_idYour clientId. Always included.
redirect_urlThe redirectUrl from the logout configuration, if provided.
stateThe state from the logout configuration, if provided.

Post-Logout Redirect URL

After the Wristband Logout Endpoint ends the user's Wristband auth session, Wristband redirects the user to your Login Endpoint by default, which starts a new login.

To send users somewhere else after logout, such as a marketing page, set redirectUrl in the logout configuration. The SDK passes it to the Wristband Logout Endpoint, and Wristband redirects the user there instead. This only controls where the user goes after Wristband's side of the logout; your Logout Endpoint must still destroy the application session itself.

For example, using the Express Auth SDK:

const logoutUrl = await wristbandAuth.logout(req, res, {
  redirectUrl: 'https://yourapp.io/goodbye',
  refreshToken,
  tenantName,
});
res.redirect(logoutUrl);

The SDK then builds the following Logout URL, and Wristband redirects the user to https://yourapp.io/goodbye after ending their auth session:

https://customer01-yourapp-yourcompany.us.wristband.dev/api/v1/logout?client_id=123&redirect_url=https://yourapp.io/goodbye

Logout State

The state value in the logout configuration lets your application carry context through the logout flow, such as why the user was logged out. The SDK appends it to the Wristband Logout URL. For example:

https://customer01-yourapp-yourcompany.us.wristband.dev/api/v1/logout?client_id=123&state=user_initiated_logout

Wristband then includes it as a state query parameter when it redirects the user to the post-logout destination. For example:

https://yourapp.io/auth/login?tenant_name=customer01&state=user_initiated_logout

This is useful for tracking logout context or showing a post-logout message.

🚧

State Length

The state value is limited to 512 characters. The SDK throws an error if it's longer.

Reference

Logout Configuration

FieldTypeDescription
redirectUrlstringWhere Wristband sends the user after ending their Wristband auth session. Also returned directly when no tenant can be resolved.
refreshTokenstringThe refresh token to revoke during logout.
statestringA value passed through the logout flow and included in the post-logout redirect. Maximum of 512 characters.
tenantCustomDomainstringThe tenant custom domain of the user's tenant. Takes priority over every other way of resolving the tenant.
tenantNamestringThe name of the user's tenant. Takes priority over everything except tenantCustomDomain.

Logout Endpoint Query Parameters

Query ParameterDescription
tenant_custom_domainThe tenant custom domain of the user's tenant.
tenant_nameThe name of the user's tenant. Only used when your loginUrl doesn't contain the {tenant_name} placeholder.


Did this page help you?