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 customfatxn 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:
Your provider authenticates the user
The user signs in with Firebase (or your OIDC provider) and your app obtains that provider’s JWT.
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.
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.Architecture
The POST /issuer/issue endpoint
Your app calls a single endpoint to exchange a provider JWT for a NEAR Auth JWT.
The JWT issued by your upstream identity provider (max 10,000 characters).
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 (seeissuer.service.ts):
- Verify the signature. The incoming
jwtis verified with RS256 against the public keys fetched fromvalidationPublicKeyUrl. If none of the keys validate the token, the service returns401 Unauthorized. - Validate the issuer. The token’s
issclaim must equal the configuredvalidationIssuerUrl. - Validate the subject. The
subclaim must be present and a non-empty string. - Validate the time claims. Unless expiration is ignored,
expmust be in the future,nbfmust not be in the future, and — when both are present —expmust be strictly afternbf. - Re-sign. The service builds a new payload and signs it with your RSA private key (RS256), then returns it as
token.
| Claim | Source in the new token |
|---|---|
sub | Copied from the incoming provider JWT |
exp | Copied from the incoming JWT (if present) |
nbf | Copied from the incoming JWT (if present) |
iss | Set to your service’s issuerUrl |
fatxn | Set to the signPayload bytes from the request |
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 typedIssuerConfig:
issuer.config.ts
| Field | Env var | Required | Description |
|---|---|---|---|
keyBase64 | KEY_BASE64 | Yes | Base64-encoded RSA private key used to sign re-issued tokens. Must decode to a PEM private key. |
validationPublicKeyUrl | VALIDATION_PUBLIC_KEY_URL | Yes | URL to fetch your provider’s public keys from (e.g. a Firebase certificate URL). Must be a valid URL. |
validationIssuerUrl | VALIDATION_ISSUER_URL | Yes | The expected iss claim on incoming JWTs (e.g. https://securetoken.google.com/<project-id>). |
issuerUrl | ISSUER_URL | Yes | The iss claim written into re-issued tokens. Must match what the CustomIssuer Guard expects. |
ignoreExpiration | IGNORE_EXPIRATION | No | When "true", skips exp/nbf validation on incoming tokens. Intended for testing only. |
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.
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.