Outseta handles your users, subscriptions, and authentication. But what about data that lives outside Outseta? When you store your own data — in Supabase, Xano, Airtable, or your own backend — you need a secure way to connect that data to the right user.

This guide explains when and why you need server-side token verification, using a practical example.

Scenario: A membership site with comments

Imagine you're building a membership community or content site. Outseta handles authentication and billing, but members can leave comments on articles. Those comments live in your own database.

You need two API endpoints:

  • GET /api/comments?articleId=123 — fetch comments for an article
  • POST /api/comments — submit a new comment

The question: How does your API know who is posting the comment? How do you prevent someone from posting as another user?

Why you can't just trust the request

Without verification, anyone may send a request claiming to be any user:

POST /api/comments
{
"userId": "someone-elses-id",
"articleId": "123",
"text": "This is a fake comment"
}

Your API has no way to know if that's legitimate. This is a security risk — users could impersonate others, spam your system, or manipulate data.

The solution: JWT Access Tokens

When a user logs in via Outseta, they receive a JWT (JSON Web Token) Access Token. This token is cryptographically signed by Outseta — it cannot be forged.

Your backend verifies the signature to confirm that the token is unmodified, and we can trust its contents, including the user identity.

Key concept: Decode ≠ Verify

Anyone can decode a JWT and see its contents — try it yourself at jwt.io. But decoding doesn't prove the token is real.

Only verification proves that Outseta actually issued the token and hasn't been tampered with. Never trust a decoded token without verification.

👉 For the complete Outseta JWT payload structure, see The JWT Access Token

How to get a token for testing

To see your own access token, log into your Outseta-powered site, open your browser's developer console, and run:

Outseta.getAccessToken()

This returns the JWT Access Token for the currently logged-in user. You can decode it at jwt.io to see the payload, but remember that your API must verify it before trusting its contents.

The authentication flow

Here's how the pieces fit together when a user posts a comment:

Sequence diagram showing the authentication flow: Browser logs in via Outseta, receives JWT, sends request to your API with token, API verifies with Outseta, then saves to database

  1. User logs in — via Outseta's login embed on your site
  2. Receives JWT — Outseta returns a signed access token to the browser
  3. Browser makes a request — sends the token in the Authorization header
  4. API verifies token — checks the signature against Outseta's public keys
  5. Token valid — signature matches, token hasn't expired
  6. Extract user ID — the sub claim contains the user's unique ID
  7. Save to database — store the comment with the verified user ID
  8. Return response — confirm success to the browser

Do you need server-side verification?

Not every Outseta integration requires server-side token verification. Here's when you do and don't need it:

Scenario Need server-side verification?
Showing/hiding UI based on login status No — use Outseta.js client-side
Gating content behind a paywall (soft) No — use protected content
Gating content behind a paywall (hard) Yes — verify before returning the page/content
Storing simple user preferences or attributes No — use custom properties
Storing relational data in your own database (e.g., comments, posts) Yes
Accepting user input that writes to your own database Yes
Protecting serverless functions or API routes Yes
Integrating with third-party services using user identity Yes

Soft vs. hard gating: Soft gating hides content client-side — it's quick to set up and works for most membership sites. Hard gating verifies the user on the server before the content is sent to the browser — use this when the content itself is sensitive and must never reach unauthorized users.

If your needs are covered by protected content or custom properties, you may not need to implement server-side verification at all.

Two ways to verify tokens

Outseta provides two methods to verify JWT Access Tokens:

Method Best for Trade-offs
JWK verification High-traffic apps, performance-critical endpoints Slightly more complex setup; token payload user data only
Profile endpoint Simpler setup, when you need custom properties, or full profile on user Network requests per verification

👉 For implementation details with JS code examples, see Verify Outseta JWT Access Tokens server-side

What's inside the token?

Once verified, you can use these (and more) claims from the token payload to identify the user:

  • sub — the user's unique Person ID (use this as your user identifier)
  • email — the user's email address
  • name — the user's full name
  • outseta:accountUid — the account they belong to
  • outseta:planUid — their subscription plan

👉 Full payload reference: The JWT Access Token

Putting it together

Here's what your comments endpoint looks like conceptually:

// POST /api/comments endpoint

1. Get the token from the Authorization header
token = request.headers["Authorization"].replace("Bearer ", "")

2. Verify the token (using JWK or profile endpoint method)
payload = verifyToken(token)

3. Extract the user ID from the verified payload
userId = payload.sub

4. Save the comment with the verified user ID
INSERT INTO comments (user_id, article_id, text)
VALUES (userId, request.body.articleId, request.body.text)

5. Return success

The key insight: you never trust user-provided identity. Instead, you extract the user ID from the verified token — this guarantees it's authentic.

Related articles

👉 Verify Outseta JWT Access Tokens server-side — Implementation guide with code examples
👉 The JWT Access Token — Full payload reference
👉 Outseta's Well-Known Endpoints (JWK / OIDC) — Technical reference for JWKS and OIDC configuration
👉 Supabase + Outseta Auth with RLS — Database-specific implementation example