Skip to content

JWT

Issues signed JWTs for the current session and publishes a JWKS so other services can verify them without calling back. Mirrors the TS jwt() plugin.

Enable

python
from better_auth import BetterAuth
from better_auth.plugins_ext import JWTPlugin

auth = BetterAuth(
    secret="a-strong-32-character-minimum-secret",
    plugins=[JWTPlugin(expiration_time="15m")],
)

Options

OptionTypeDefaultDescription
remote_urlstr | NoneNonePoint /jwks consumers at a remote JWKS instead of local keys.
key_pair_configdict | NoneNone ({"alg": "EdDSA", "crv": "Ed25519"})Key algorithm config; the TS JWKOptions union: EdDSA/Ed25519, ES256, ES512, PS256, RS256.
disable_private_key_encryptionboolFalseStore private keys unencrypted.
rotation_intervalint | NoneNoneRotate the signing key every N seconds.
grace_periodint2592000How long rotated-out keys stay in the JWKS (30 days).
jwks_pathstr"/jwks"Route where the JWKS is published.
issuerstr | NoneNone (base_url)iss claim.
audiencestr | list[str] | NoneNone (base_url)aud claim.
expiration_timeint | float | datetime | str"15m"Token lifetime (seconds or a duration string).
define_payloadcallable | NoneNoneCustom payload builder from the session.
get_subjectcallable | NoneNoneCustom sub claim (defaults to the user id).
signcallable | NoneNoneReplace the signing routine entirely.
disable_setting_jwt_headerboolFalseDon't attach set-auth-jwt on /get-session responses.

Endpoints

MethodPath
GET/jwks (at jwks_path)
GET/token

Schema

TableColumns
jwksid, publicKey, privateKey, createdAt, expiresAt

Notes

  • Storage parity: the privateKey codec is byte-compatible with TS — a jwks row written here is readable by a TS app sharing the database and vice versa. alg/crv are not persisted (TS declares no such columns); they are reconstructed from key_pair_config on read.
  • Required by OAuth Provider unless that plugin is configured with disable_jwt_plugin=True.

MIT licensed · API-compatible with better-auth