Skip to main content
Most NEAR Auth integrations use the Auth0 happy path, where Auth0 issues the JWT and the on-chain Auth0 Guard verifies it. The custom issuer service is the advanced, non-Auth0 alternative: a small backend you run that takes a JWT from an external identity provider — Firebase, a custom OIDC provider, or anything that issues RS256 tokens — validates it, and re-signs a brand-new JWT with a key you control. That re-issued token is what the on-chain CustomIssuer Guard verifies. The guard never trusts your upstream provider directly; it only trusts tokens signed by your issuer’s key, which is registered on-chain through attestation.
The custom issuer service is required whenever you use the CustomIssuer Guard. The guard verifies JWTs signed by this service — not the tokens your identity provider originally issued.

Why an intermediary issuer

The NEAR Auth JWT format carries a custom fatxn claim: the encoded transaction (or delegate action) payload that the guard binds the signature to. External providers like Firebase don’t know about NEAR Auth and won’t put a fatxn claim in their tokens. They also sign with keys you don’t control, which makes on-chain key management and rotation awkward. The custom issuer service solves both problems. It sits between your provider and the NEAR Auth contracts as a JWT re-signing proxy:
1

Your provider authenticates the user

The user signs in with Firebase (or your OIDC provider) and your app obtains that provider’s JWT.
2

The issuer validates the provider's JWT

Your service verifies the token’s signature against the provider’s public keys and checks its issuer and time claims.
3

The issuer re-signs a NEAR Auth JWT

It mints a new RS256 token that preserves the user’s identity, embeds the transaction payload as fatxn, and is signed with your own private key.
4

The CustomIssuer Guard verifies on-chain

Your app calls FastAuth.sign(…); the guard checks the token against your issuer’s public key, which lives on-chain via attestation.
This lets you use any compliant identity provider while keeping full control over the signing keys that NEAR Auth ultimately trusts, and gives you a place to add custom validation before a token is ever accepted.

Architecture

The service is a small NestJS backend. It fetches your provider’s public keys from a URL you configure, verifies incoming tokens against them, and re-signs new tokens with an RSA private key you supply. The corresponding public key is registered with the CustomIssuer Guard through the Attestation contract, so the guard can verify tokens the service produces.

The POST /issuer/issue endpoint

Your app calls a single endpoint to exchange a provider JWT for a NEAR Auth JWT.
Response
string
required
The JWT issued by your upstream identity provider (max 10,000 characters).
number[]
required
The encoded transaction or delegate-action payload, as an array of bytes (each 0–255). The service copies this into the fatxn claim of the re-issued token so the guard can bind the eventual signature to exactly this payload.

What happens on each request

When a request arrives, the service runs the following flow (see issuer.service.ts):
  1. Verify the signature. The incoming jwt is verified with RS256 against the public keys fetched from validationPublicKeyUrl. If none of the keys validate the token, the service returns 401 Unauthorized.
  2. Validate the issuer. The token’s iss claim must equal the configured validationIssuerUrl.
  3. Validate the subject. The sub claim must be present and a non-empty string.
  4. Validate the time claims. Unless expiration is ignored, exp must be in the future, nbf must not be in the future, and — when both are present — exp must be strictly after nbf.
  5. Re-sign. The service builds a new payload and signs it with your RSA private key (RS256), then returns it as token.
The re-issued token deliberately preserves the caller’s identity while re-anchoring trust to your issuer:
The iss of the re-issued token is your service’s own issuerUrl, not the upstream provider’s. This is the value the CustomIssuer Guard checks on-chain, so it must match the issuer you configure in the guard.

Configuration

The service reads its settings from environment variables into a typed IssuerConfig:
issuer.config.ts
ignoreExpiration disables time-claim checks on incoming JWTs. Keep it false in production — an expired provider token would otherwise be re-issued as a fresh NEAR Auth token.

Example (Firebase)

.env

Generate a signing key

The service signs with a 2048-bit RSA key. Generate the pair, then register the public half with the guard through attestation.

When to use this path

Reach for the custom issuer service when the Auth0 happy path doesn’t fit:

You already use Firebase

Your users authenticate with Firebase Authentication and you want them signing NEAR transactions without adding Auth0.

You run your own OIDC

You operate a custom OIDC-compliant provider and want to bridge its RS256 tokens into NEAR Auth.

You need to own the keys

You want full control over the signing keys NEAR Auth trusts, and to manage rotation through attestation.

You need custom validation

You want to enforce extra checks on a user before any signable token is ever minted.
If none of these apply, prefer the simpler Auth0 setup — no service to run, no keys to manage. See the Auth0 concept and how it works.
Deploy the service behind HTTPS, restrict CORS with ALLOWED_ORIGINS, add rate limiting, and store KEY_BASE64 in a secrets manager. The private key is the root of trust for every signature the CustomIssuer Guard will accept.

Next steps

CustomIssuer Guard

The on-chain guard that verifies tokens re-signed by this service.

Attestation

How your issuer’s public key is registered and rotated on-chain.

JWT format

The RS256 claims — including fatxn — that guards verify.