# Tokens & JWTs

How SurrealDB authenticates clients with JWTs, DEFINE ACCESS TYPE JWT, symmetric and asymmetric verification, claims as session variables, and RECORD access for database-managed sign-in.

SurrealDB can authenticate clients using **JSON Web Tokens (JWTs)**. Your application or identity provider issues a signed JWT; SurrealDB verifies the signature and builds a **session** from the token’s claims so subsequent queries run with the correct identity and scope. The same mechanism applies whether the client connects over HTTP, WebSocket, or other supported interfaces: the token establishes **who** is calling before **authorisation** runs.

You register JWT-based access with **`DEFINE ACCESS … TYPE JWT`** (see [`DEFINE ACCESS`](/docs/reference/query-language/statements/define/access.md)). SurrealDB validates the token’s signature and standard claims (such as issuer and audience) according to your definition. Verification supports **symmetric** algorithms such as **HS256** with a shared secret, and **asymmetric** algorithms such as **RS256** and **ES256** using a configured public key or JWKS - matching how major providers sign tokens at scale. Choose the model that matches your key management: shared secrets for internal services, public-key verification when keys are rotated by an external IdP.

A typical JWT access definition names:

- The signing method (for example HS256 with a secret, or RS256/ES256 with a public key or JWKS URL).
- Expected **issuer** and **audience** values so only tokens minted for your deployment are accepted.
- How claim names map into session data (so **`$auth`** exposes fields your [`PERMISSIONS`](/docs/learn/security/authorization/permissions-and-row-level-security.md) rules can use).

**Claims** from the JWT are mapped into SurrealDB **session variables** (including **`$auth`**) so [permissions](/docs/learn/security/authorization/permissions-and-row-level-security.md) and queries see a consistent view of the user whether authentication came from SurrealDB or from elsewhere. Typical mappings include subject, roles, and custom namespaces your application relies on for **authorisation**. The exact claim names depend on your issuer; configure the mapping in `DEFINE ACCESS` so your policies read stable fields regardless of whether the upstream token uses flat or nested JSON.

That design works well with **third-party identity providers** - Auth0, AWS Cognito, Okta, Azure AD, and similar systems that issue OIDC/OAuth2 JWTs. You configure issuer, audience, signing keys, and claim bindings once; users authenticate with the provider, receive a JWT, and present it to SurrealDB without storing end-user passwords in your database.

Keep token lifetimes and key rotation in mind: short-lived access tokens and explicit issuer/audience checks reduce the impact of a leaked JWT, and asymmetric verification lets SurrealDB trust keys published via JWKS when your provider rotates them.

When you need **database-managed authentication** (for example sign-up and credential checks implemented as part of your data model), use **`DEFINE ACCESS … TYPE RECORD`**. That path issues and validates access in coordination with records in your database while still producing a session compatible with the same permission model as JWT access. Many deployments combine both: system operators use **root** or scoped database users, end users authenticate via **RECORD** or brokered **JWT** access, and **`PERMISSIONS`** enforce row- and field-level rules for everyone.

In practice, teams often start with **HS256** and a single secret for development or private networks, then move to **RS256** or **ES256** with JWKS in production so verification does not depend on long-lived shared secrets crossing service boundaries. The [`DEFINE ACCESS`](/docs/reference/query-language/statements/define/access.md) reference lists the exact clauses for each approach.

For how authentication fits the wider security model, read the [authentication overview](/docs/learn/security/authentication/overview.md). For every option on JWT and record access, use the reference for [`DEFINE ACCESS`](/docs/reference/query-language/statements/define/access.md).
