This guide walks through how a backend can maintain a parallel authentication system using JSON Web Tokens (JWTs), while Para manages wallet session data. The result is a two-layer approach:

  1. Para session for wallet-based access,
  2. A backend-issued JWT for user identity, roles, and permissions.

Overview

When your frontend obtains a valid Para session, it can then pass that session to your backend, which imports and verifies it via the Para SDK. If valid, the backend either creates or updates its own user record (correlating the user’s internal ID with their Para user ID) and issues a JWT. The frontend will store and send both the JWT and the Para session on subsequent requests. The backend then verifies both the JWT signature and the active Para session, ensuring consistency between the two credentials.

Sequence Diagram

Below is a sequence diagram illustrating the high-level flow, starting from initial Para login in the frontend to maintaining a parallel JWT in the backend:

For a more thorough and advanced sequence diagram with additional details check out this

Kroki Mermaid Editor

.

Implementation Steps

1

Frontend Para Login

Use the Para Modal via @getpara/react-sdk for a pre-built authentication interface, or create a custom UI with @getpara/web-sdk to authenticate users. After successful login, export the Para session:

const paraSession = para.exportSession();

For more details on sessions, see our Session Management guide.

2

Send Para Session to Backend

Perform a POST /auth/login (or similar endpoint) with paraSession in the body. Your backend will then validate the session:

const imported = para.importSession(paraSession);
const isActive = imported.isActiveSession();

if (!isActive) {
  return res.status(401).json({ error: "Session invalid or expired" });
}
// Extract relevant user data, upsert in DB, generate JWT

The para session contains the signer, if you don’t intend on signing on the backend, you should remove the signer from the session before sending it to the backend. An example of how to do this is:

// decode the para session and remove the signer
const { signer, ...rest } = JSON.parse(atob(paraSession))
// encode the para session without the signer
const paraSessionWithoutSigner = btoa(JSON.stringify(rest));

You can then send paraSessionWithoutSigner to the backend.

3

Generate a JWT

If the session is active, generate a JWT with the following user claims:

jwt
Claims Object

The backend returns the JWT (and optionally the user profile) to the frontend.

4

Subsequent Requests

For all authenticated requests, the frontend must include:

headers
Headers Object

The backend verifies both the JWT and calls isActiveSession on the Para session. The request proceeds only if both are valid and match.

5

Session Renewal

When the JWT expires but the Para session remains valid:

  1. Backend prompts frontend to re-authenticate
  2. Frontend refreshes or re-exports the Para session
  3. Frontend requests a new JWT from the backend using the refreshed session

Always verify both JWT and Para session validity to maintain secure authentication.

Database Considerations

How you store or update user data is up to you:

  • New Users: Create a record linking para_user_id with your own internal user ID.
  • Existing Users: Update fields like last_login, auth_method, or auth_identifier.
  • JWT Storage: Typically, JWTs are stateless. You might store a token blacklist or rely on short expiry times.

Your database schema and logic are entirely up to you. The critical step is ensuring you map para_user_id to an internal user record and sync any necessary data (e.g., username, email, etc.).

Best Practices

  • Use HTTPS: Always secure these flows with TLS.
  • Short-Lived JWT: Keep JWT expiry shorter or equal to the Para session expiry, forcing re-validation.
  • Validate Consistency: Confirm the para_user_id and auth_identifier in the Para session matches the data in your JWT claims.
  • Handle Refresh: If the Para session is still active but your JWT expired, allow a quick refresh to avoid forcing the user to re-login.

Example Flow Recap

  1. Frontend logs in with Para, exports session, and sends it to the backend.
  2. Backend imports session, verifies it, upserts user data in the DB, and issues a JWT.
  3. Frontend stores and uses both JWT + Para session for subsequent calls.
  4. Backend cross-checks both, ensuring layered security.
  5. On expiry, the frontend can refresh the session with Para and obtain a new JWT from the backend.