> ## Documentation Index
> Fetch the complete documentation index at: https://stytch.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Authenticate a session

> How to validate session tokens and JWTs on your backend.

## Use case

* **Protect server-side endpoints:** Validate either the `session_token` or `session_jwt` on requests to your backend before proceeding with the request.
* **Backend authorization checks:** Enforce RBAC permissions and perform server-side user authorization checks before proceeding with the request.

***

## JWT vs. session token validation

Since `session_jwt` and `session_token` are stored in the site's cookies, the browser will include these cookies in the request headers to your backend if they share a domain.

Select between validating a JWT or session token:

<Tabs>
  <Tab title="Validate a JWT">
    Using JSON Web Tokens (JWT) over opaque session tokens **allows you to validate the token locally entirely within your backend service**, which is significantly faster than communicating with Stytch's API on every user session validation check.

    ### Reasons to use JWTs

    * **Minimize latency:** JWTs can be locally validated to authenticate sessions without an API call (until it expires).
    * **Authorize actions outside your app:** JWTs contain standard claims and information about the User Session.

    ***

    ### Using the Stytch SDK

    <Frame caption="Session validation using authenticateJwt()">
      <img src="https://mintcdn.com/stytch-34ca0595/F3sfuxsAeAZ7fNRj/images/sessions/jwt-validation.png?fit=max&auto=format&n=F3sfuxsAeAZ7fNRj&q=85&s=1b3e63e3b49b68ba4d44f7202d9c41fa" alt="JWT validation flow" width="6903" height="2828" data-path="images/sessions/jwt-validation.png" />
    </Frame>

    <Steps>
      <Step title="Initialize the SDK">
        Upon initialization, the Stytch SDK client will automatically retrieve and cache your JSON Web Key Set (JWKS) for use in local JWT validation.

        <Warning>Persist the SDK client instead of reinitializing it between requests so your JWKS is only fetched once.</Warning>
      </Step>

      <Step title="Validate JWTs using either SDK method">
        <Columns col={2}>
          <Card title="authenticateJwt()" href="/api-reference/consumer/api/sessions/authenticate-jwt">
            Handles the local JWT authentication and remote session authentication fallback.

            **Recommended**
          </Card>

          <Card title="authenticate()" href="/api-reference/consumer/api/sessions/authenticate-session">
            Always communicates with the Stytch API to authenticate a session.
          </Card>
        </Columns>
      </Step>

      <Step title="Using authenticateJwt() example">
        ```javascript Node.js icon="node-js" lines theme={null}
        const express = require('express');
        const cookieParser = require('cookie-parser');

        const app = express();
        app.use(cookieParser());
        app.use(authenticateStytchSession);

        const client = new stytch.Client({
          project_id: process.env.STYTCH_PROJECT_ID,
          secret: process.env.STYTCH_SECRET,
        });

        const authenticateStytchSession = (req, res, next) => {
        return client.sessions.authenticateJwt({ session_jwt: req.cookies['stytch_session_jwt'] })
          .then(session => {
            req.stytchSession = session;
            return next();
          })
          .catch(next)
        };
        ```
      </Step>

      <Step title="Retrieving user data when validating locally" icon="info">
        `authenticateJwt()` does not return the full [User object](/api-reference/consumer/api/users/user-object) when validated locally. If you need data from the User object to complete additional authorization checks or any other additional action, use [custom claims](/consumer-auth/manage-sessions/custom-claims) to add it to the JWT itself.
      </Step>
    </Steps>

    ***

    ### Using custom backend JWT validation

    Stytch JWTs are compatible with other standard JWT validation libraries. You'll need to:

    * Implement logic to fall back to Stytch's [Authenticate Session](/api-reference/consumer/api/sessions/authenticate-session) endpoint when the JWT is expired. You can refer to the [Authenticate JWT](/api-reference/consumer/api/sessions/authenticate-jwt) method for what that logic might look like.

    * Supply your validation library the Stytch [Get JWKS](/api-reference/consumer/api/sessions/get-jwks) endpoint for [JWKS rotation](#json-web-key-set-jwks-rotation). Otherwise, your application should decide which JWKS to use for validation by inspecting the JWT and JWKS `kid` value.

    <Accordion title="Common libraries">
      - [jose](https://www.npmjs.com/package/jose) (Node.js)
      - [jwt](https://pkg.go.dev/github.com/golang-jwt/jwt) (Go)
      - [Hasura](https://hasura.io/docs/2.0/auth/authentication/jwt/)
      - [NGINX](https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-jwt-authentication/)
      - [Apollo](https://www.apollographql.com/docs/router/configuration/authn-jwt/)
      - [php-jwt](https://packagist.org/packages/firebase/php-jwt)
    </Accordion>

    <Note>We strongly recommend using our [backend SDKs](/api-reference/consumer/api/sdks) (available in Python, Node, Ruby, Go, and Java) for JWT validation. Our libraries handle the logic to authenticate JWTs locally and automatically fall back to the Stytch API when the JWT is expired.</Note>

    ***

    ### JSON Web Key Set (JWKS) rotation

    Stytch automatically rotates your JWKS every 6 months for security purposes. Newly minted JWTs will be signed using the new key set. **Both key sets** will be returned by the [Get JWKS](/api-reference/consumer/api/sessions/get-jwks) endpoint for a 1 month grace period.

    * \~1 month before your Project's old JWKS expires, a new JWKS will be automatically generated.
    * When this happens, there will be a 5 minute period where some JWTs will be signed by the old JWKS and some by the new, due to the JWT set lifetime.
    * Match the `kid` value of the JWT and JWKS to determine the correct JWKS to use for validation.
    * Most JWT libraries have a mechanism to handle this automatically; if not, you may see errors like `"kid" invalid, unable to lookup correct key` (depending on the library and version you use).

    <Check>Stytch's [backend SDKs](/api-reference/consumer/api/sdks) handle JWKS rotation for you automatically.</Check>
  </Tab>

  <Tab title="Validate a session token">
    Session tokens are considered opaque because they don't contain any information about the underlying User Session.

    ### Reasons to use session tokens

    * **Strict security requirements:** Session tokens cannot be locally validated. You must always make a Stytch API call to authenticate the token, which guarantees that the token is valid at that point in time. This provides stricter guarantees than JWTs, which have a 5-minute window where the underlying User Session may have been revoked before the JWT was refreshed.

    ***

    ### Using the Stytch SDK

    <Steps>
      <Step title="Validate a session token using the Authenticate Sessions method">
        <Columns col={2}>
          <Card title="authenticate()" href="/api-reference/consumer/api/sessions/authenticate-jwt">
            Always communicates with the Stytch API to authenticate a session.
          </Card>
        </Columns>
      </Step>

      <Step title="Using Authenticate Sessions example">
        ```python lines theme={null}
        def upgrade_user_to_coordinator():
          try:
            resp = client.sessions.authenticate(
              session_token=session['stytch_session'],
              custom_claims={
                "role": "coordinator",
                "read-scope": ["appointments", "deliveries"],
                "write-scope": ["calendar"]
              }
            )
            if resp.status != 200:
              return handle_error(resp.status)
            session['stytch_session'] = resp.session_token
            return
          except Exception as e:
            return handle_exception(e)
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>
