# Apply for production access
Source: https://docs.auth.near.org/home/apply
Get your app whitelisted for NEAR Auth on mainnet with dedicated production credentials.
Going live on **mainnet requires whitelisting**: NEAR Auth issues you dedicated production Auth0 credentials and grants access to the mainnet contracts. This page explains what you get and walks you through the approval process.
Building locally? You can develop against testnet using the values in [Resources → Testnet](/resources/testnet), then come back here when you're ready to ship on mainnet.
***
## What whitelisting grants you
On **mainnet**, each production app gets its **own** Auth0 domain, `clientId`, and `signingAudience`, plus access to the mainnet NEAR Auth contract at `fast-auth.near`. This is what the whitelisting process below grants you.
| Item | What you receive |
| ----------------------- | ---------------------------------------------------------------- |
| **Auth0 credentials** | Dedicated production `domain`, `clientId`, and `signingAudience` |
| **Contract access** | Access to the mainnet NEAR Auth contract at `fast-auth.near` |
| **Deployment guidance** | Support for taking your integration to production |
***
## Apply for production access
Open the application form to request mainnet whitelisting for your app.
***
## How the approval process works
Fill out the [production access form](https://form.typeform.com/to/VWHjf3HV) with details about your app and how you plan to use NEAR Auth. See [what to prepare](#what-to-prepare) below so you can fill it out in one pass.
The NEAR Auth team reviews your submission and may reach out for additional information about your use case or expected volume.
Once approved, you receive everything you need to go live:
* **Production Auth0 credentials** — your dedicated `domain`, `clientId`, and `signingAudience` (the JWT `aud`).
* **Access to the mainnet NEAR Auth contract** at `fast-auth.near`.
* **Guidance for production deployment.**
Drop your production credentials into your provider config with `network: "mainnet"` — the rest of your integration stays the same.
***
## What to prepare
Have these details ready before you open the form so you can submit in a single pass. Each field maps to a setting on your production application.
The name NEAR Auth displays to your users during login and when they approve a transaction. Use the public-facing name you want people to recognize — e.g. *Acme Wallet*.
A short summary of what your application does. It appears next to your name on the NEAR Auth login and transaction-approval screens, so write it for end users. One or two sentences.
A square logo shown alongside your app name on the login and approval screens. Provide a PNG or SVG (recommended 256×256 px) served over HTTPS. A recognizable logo helps users trust the request.
Your best estimate of monthly active users (MAU). This lets us provision capacity and set appropriate rate limits for your app. Choose one bracket: **Less than 1,000**, **1,000–10,000**, **10,000–25,000**, or **more than 25,000**.
The exact HTTPS URL NEAR Auth is allowed to redirect back to after login and after a signature request. It **must match the `redirectUri` you configure in the SDK**. Any redirect to a non-whitelisted URL is rejected. Example: `https://app.example.com/callback`.
*Optional.* An HTTPS URL users may be returned to after logging out. Only needed if you pass a return URL when calling `logout`; leave it blank otherwise. Example: `https://app.example.com`.
The origin — scheme + domain, no path — where your app is served and from which it calls NEAR Auth. Used to authorize your domain and enforce CORS, so only your app can start the auth flow. Must be HTTPS. Example: `https://app.example.com`.
A monitored email for the person we should contact about your application: approval, credential delivery, quota changes, and security notices. Example: `dev@example.com`.
**Multiple environments** — the Callback URL, Logout URL, and Web Origin fields each accept several comma-separated values, so you can register your production and staging URLs together. Developing locally? You don't need this form for testnet — use the shared [testnet credentials](/resources/testnet).
**HTTPS is required** for the Callback, Logout, and Web Origin URLs on mainnet. Plain `http://` URLs are rejected.
***
## Go live on mainnet
Once you're whitelisted, point your provider at mainnet using your production credentials.
```ts main.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
const provider = new JavascriptProvider({
network: "mainnet",
clientId: "",
// domain and signingAudience default from the mainnet network,
// override them only if your production credentials differ.
});
```
Use the mainnet contract account ids when you construct the client:
```ts client.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthClient } from "@fast-auth-near/browser-sdk";
const client = new FastAuthClient(provider, connection, {
fastAuthContractId: "fast-auth.near",
mpcContractId: "v1.signer",
});
```
Production requires your own approved credentials. Only the dedicated `clientId`, domain, and signing audience you receive from whitelisting will authenticate against the mainnet NEAR Auth contract.
***
## Next steps
Compare testnet and mainnet configuration side by side.
Production contract addresses, RPC, and explorer links.
Shared testnet credentials to keep building right now.
Wire up login and logout with your provider.
# Authenticate your users
Source: https://docs.auth.near.org/home/guides/authenticate-users
Log users in with a Web2 identity, check their session on page load, and log them out — with the React and Browser SDKs.
Authentication is the first thing your app does with NEAR Auth: sign a user in through Auth0, remember them across page loads, and sign them out when they're done. Once a user is authenticated you can request a signer and [sign NEAR transactions](/home/guides/sign-transactions) on their behalf.
This guide shows the full login lifecycle for both SDKs. Pick the one that matches your stack — the concepts are identical, only the wiring differs.
All examples use **mainnet** and the Auth0 (JavaScript) provider. Mainnet requires approved credentials — [apply for access](/home/apply) to get your Auth0 client id. See [Choose your SDK](/home/guides/choose-your-sdk) if you're not sure which library fits your app.
Building locally? You can develop against testnet using the values in [Resources → Testnet](/resources/testnet).
***
## How login works
NEAR Auth authenticates users through **Auth0**. Under the hood, the `JavascriptProvider` wraps Auth0's SPA client and handles the OAuth handshake for you.
The SDK opens Auth0 in a **popup** (the default) or via a full-page **redirect**, where the user signs in with Google, Apple, email, or a passkey.
On success, Auth0 issues a JWT and the provider derives a stable user identity (the token's `sub` claim). With redirect login, the SDK completes the handshake automatically when the user lands back on your app.
Auth0 persists the session in the browser, so a returning user stays logged in across reloads until they log out or the session expires.
Redirect login navigates the browser away to Auth0 and back. On the return trip you **must** re-check the login status on page load (`isLoggedIn()`) so the SDK can finish the handshake and your UI reflects the authenticated state. Popup login keeps the user on your page and returns control to the same call.
***
## Set up and authenticate
Install the [React SDK](/sdks/react-sdk) and the JavaScript provider, then wrap your app in `FastAuthProvider`.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/react-sdk @fast-auth-near/javascript-provider near-api-js
```
### Wrap your app in the provider
Create a `JavascriptProvider`, open a NEAR `Connection`, and pass both to `FastAuthProvider`. The provider builds a `FastAuthClient` for you and makes it available through hooks anywhere in the tree.
```tsx App.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthProvider } from "@fast-auth-near/react-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
import { connect } from "near-api-js";
import { useEffect, useState } from "react";
import type { Connection } from "near-api-js";
const provider = new JavascriptProvider({
network: "mainnet",
clientId: "",
});
export default function App() {
const [connection, setConnection] = useState(null);
useEffect(() => {
connect({
networkId: "mainnet",
nodeUrl: "https://rpc.mainnet.near.org",
}).then(({ connection }) => setConnection(connection));
}, []);
if (!connection) return
Connecting to NEAR…
;
return (
);
}
```
`network="mainnet"` tells the client which deployed contracts to use — it resolves `fast-auth.near` and the mainnet MPC signer for you, so you don't pass contract ids in React.
### Log in and read session state
Two hooks cover the whole lifecycle:
* `useFastAuth()` → `{ client, isReady }` — the underlying `FastAuthClient` and whether it has finished initializing.
* `useIsLoggedIn()` → `{ isLoggedIn, isLoading, error, refetch }` — the current session status. It **checks automatically on mount** (including finishing any redirect handshake), so a returning user is recognized without extra code.
```tsx LoginButton.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { useFastAuth, useIsLoggedIn } from "@fast-auth-near/react-sdk";
export function LoginButton() {
const { client, isReady } = useFastAuth();
const { isLoggedIn, isLoading, refetch } = useIsLoggedIn();
if (!isReady || isLoading) {
return
Loading…
;
}
if (isLoggedIn) {
return (
);
}
return (
);
}
```
Because `useIsLoggedIn()` auto-checks on mount, no extra page-load code is needed — even after a redirect login, the hook resolves to the authenticated state on its own. Call `refetch()` after a popup `login()` or after `logout()` to update the status immediately.
Install the [Browser SDK](/sdks/browser-sdk) and the JavaScript provider. The framework-agnostic `FastAuthClient` works in any web app — vanilla JS, Vue, Svelte, and more.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/browser-sdk @fast-auth-near/javascript-provider near-api-js
```
### Initialize the client
Create a `JavascriptProvider`, open a NEAR `Connection`, and construct a `FastAuthClient` with the mainnet contract ids.
```ts main.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthClient } from "@fast-auth-near/browser-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
import { connect } from "near-api-js";
const provider = new JavascriptProvider({
network: "mainnet",
clientId: "",
});
const { connection } = await connect({
networkId: "mainnet",
nodeUrl: "https://rpc.mainnet.near.org",
});
const client = new FastAuthClient(provider, connection, {
fastAuthContractId: "fast-auth.near",
mpcContractId: "v1.signer",
});
```
### Log in
Call `login()` to start the Auth0 flow. By default this opens a popup; the promise resolves once the user has authenticated.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
await client.login();
```
### Check the session on page load
On every load, ask the provider whether there's an active session. This also completes the handshake automatically if the user is returning from a redirect login, so run it before rendering your authenticated UI.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
const isLoggedIn = await provider.isLoggedIn();
if (isLoggedIn) {
// Session is active — safe to request a signer.
const signer = await client.getSigner();
} else {
// Show your sign-in button.
}
```
`client.getSigner()` throws if the user isn't logged in, so always confirm the session first with `provider.isLoggedIn()` (or handle the error). See [Sign transactions](/home/guides/sign-transactions) for what to do with the signer.
***
## Log out
Logging out clears the Auth0 session. After this the user is unauthenticated and you can no longer get a signer until they log in again.
```tsx React theme={"theme":{"light":"github-light","dark":"github-dark"}}
// From any component with the client:
const { client } = useFastAuth();
await client?.logout();
// Then refresh status, e.g. useIsLoggedIn().refetch()
```
```ts Browser theme={"theme":{"light":"github-light","dark":"github-dark"}}
await client.logout();
```
With the default popup flow, `logout()` clears the session in place. If you configured a redirect logout in Auth0, the browser navigates to Auth0 and back — re-check `isLoggedIn()` on the return so your UI updates.
***
## Next steps
Turn an authenticated user into a signer and submit NEAR transactions.
Compare the React and Browser SDKs and pick the right fit.
Providers, hooks, and the relayer-aware client.
The FastAuthClient and FastAuthSigner classes.
# Choose your SDK
Source: https://docs.auth.near.org/home/guides/choose-your-sdk
Pick the right NEAR Auth SDK and provider for your stack — React, browser, or mobile.
NEAR Auth ships as a small set of composable libraries: an **SDK** for your framework and a **provider** for your platform. You always pick one of each and combine them. This page helps you choose the pair that fits your app.
Every combination uses the same Auth0 login flow and the same on-chain contracts — the SDK shapes the developer API, and the provider adapts the login to your platform.
***
## Choose your SDK
The SDK gives you the `FastAuthClient` for logging users in and the `FastAuthSigner` for requesting signatures. Pick the one that matches your frontend framework.
| SDK | Package | Use case |
| --------------- | ----------------------------- | -------------------------------------------------------------------------- |
| **Browser SDK** | `@fast-auth-near/browser-sdk` | Vanilla JavaScript, TypeScript, Vue, Svelte, Angular, or any web framework |
| **React SDK** | `@fast-auth-near/react-sdk` | React applications that want hooks and context providers |
### Browser SDK
The Browser SDK provides a framework-agnostic, class-based `FastAuthClient` that works in any JavaScript app. Reach for it when:
* You're building with vanilla JavaScript, TypeScript, Vue, Svelte, or Angular.
* You want full control over the authentication and signing flow.
* You prefer an imperative, class-based API over hooks.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/browser-sdk
```
You instantiate `FastAuthClient` yourself, call `login()`, and pull a `FastAuthSigner` out of it with `getSigner()`.
### React SDK
The React SDK wraps the Browser SDK with React-idiomatic ergonomics: a `FastAuthProvider` you mount at the root of your app, plus hooks like `useFastAuth()`, `useIsLoggedIn()`, `usePublicKey()`, and `useSigner()`. Reach for it when:
* You're building a React application.
* You want declarative, hook-based state for the client, login status, and signer.
* You'd rather not wire up the client lifecycle by hand.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/react-sdk
```
The React SDK's signer is relayer-aware, adding `signAndSendTransaction(...)` and `signAndSendDelegateAction(...)` on top of the core signing methods.
The React SDK is built on the Browser SDK — anything the Browser SDK does, the React SDK can do too. Choose the Browser SDK only when you're not using React.
***
## Choose your provider
**Providers** are platform-specific adapters that run the actual login with Auth0. They abstract away the differences between web browsers and native mobile so the SDK stays the same. Pick the one that matches where your app runs.
| Provider | Package | Platform |
| ------------------------- | --------------------------------------- | -------------------- |
| **JavaScript provider** | `@fast-auth-near/javascript-provider` | Web browsers |
| **React Native provider** | `@fast-auth-near/react-native-provider` | iOS and Android apps |
### JavaScript provider
`JavascriptProvider` is designed for web browsers and works with either the Browser SDK or the React SDK. It handles the Auth0 OAuth flow — via popup or redirect — and token management on the web.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/javascript-provider
```
The web login uses an Auth0 popup or full-page redirect. If you use redirect mode, your app reloads on the way back from Auth0, so persist any in-progress state before requesting a login or signature.
### React Native provider
`ReactNativeProvider` is designed for iOS and Android apps. It uses native authentication flows and secure credential storage, backed by `react-native-auth0`.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/react-native-provider
```
***
## How SDKs and providers combine
Your dApp talks to an **SDK** (`FastAuthClient` / `FastAuthSigner`), which delegates the login to a **provider** (the Auth0 adapter for your platform). The provider talks to Auth0; the SDK talks to the NEAR Auth contracts.
```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
Your dApp ─▶ NEAR Auth SDK ─▶ Provider ─▶ Auth0
(FastAuthClient / (JavascriptProvider /
FastAuthSigner) ReactNativeProvider)
```
You construct a provider and pass it into the SDK. Here's how the three supported pairings install:
```bash React (web) theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/react-sdk @fast-auth-near/javascript-provider near-api-js
```
```bash Browser (web) theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/browser-sdk @fast-auth-near/javascript-provider near-api-js
```
```bash React Native (mobile) theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/react-sdk @fast-auth-near/react-native-provider
```
This gives you three practical combinations:
| Your app | SDK | Provider |
| ----------------------- | ----------------------------- | --------------------------------------- |
| React on the web | `@fast-auth-near/react-sdk` | `@fast-auth-near/javascript-provider` |
| Any other web framework | `@fast-auth-near/browser-sdk` | `@fast-auth-near/javascript-provider` |
| React Native mobile | `@fast-auth-near/react-sdk` | `@fast-auth-near/react-native-provider` |
The SDK and provider are chosen independently: the SDK follows your **framework** (React vs. everything else), and the provider follows your **platform** (web vs. mobile).
***
## Reference each library
`FastAuthProvider`, hooks, and the relayer-aware signer for React apps.
The framework-agnostic `FastAuthClient` and `FastAuthSigner` classes.
`JavascriptProvider` — the Auth0 adapter for web browsers.
`ReactNativeProvider` — the Auth0 adapter for iOS and Android.
Once you've picked a pair, wire it up and sign your first transaction in under 5 minutes.
# Sign transactions & delegate actions
Source: https://docs.auth.near.org/home/guides/sign-transactions
Request MPC signatures for NEAR transactions and gasless delegate actions after a user logs in with NEAR Auth.
Once a user is [authenticated](/home/guides/authenticate-users), your app can request signatures for NEAR transactions on their behalf. You never touch a private key — you ask the user to approve a payload through Auth0, and a [Multi-Party Computation network](/protocol/concepts/mpc) produces the signature after the [NEAR Auth contract](/protocol/contracts/fast-auth) verifies the approval on-chain.
This guide covers the two ways to sign: a **transaction signature** you submit yourself, and a **delegate action signature** a [relayer](/protocol/concepts/relayer) can submit gaslessly on the user's behalf.
`requestTransactionSignature` and `requestDelegateActionSignature` may trigger a **browser redirect or open a popup**, depending on the SDK and how you configured the Auth0 provider. Design your UX to expect this context switch — persist any in-progress state and resume it on your callback route so the flow survives a full-page redirect.
***
## Get a signer
After login, obtain a `FastAuthSigner` from the client. The signer is bound to the logged-in identity and is what you use to request signatures, derive keys, and build the on-chain call.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
const signer = await client.getSigner();
```
Use the `useSigner` hook — it reads the client from `FastAuthProvider` and tracks loading and error state for you.
```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { useSigner } from "@fast-auth-near/react-sdk";
function SignButton() {
const { signer, isLoading, error } = useSigner();
if (isLoading) return Loading signer…;
if (error) return Error: {error.message};
if (!signer) return Please log in;
return ;
}
```
***
## Request a transaction signature
Build a standard `near-api-js` transaction, then hand it to the signer. Use `getPublicKey()` to fetch the sender's MPC-derived key so the transaction is built against the correct account.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { transactions } from "near-api-js";
const publicKey = await signer.getPublicKey();
// Build your transaction
const transaction = transactions.createTransaction(
"sender.near", // Sender account
publicKey, // Sender's MPC-derived public key
"receiver.near", // Receiver account
nonce, // Account nonce
[
transactions.transfer(BigInt("1000000000000000000000000")), // 1 NEAR
],
blockHash, // Recent block hash
);
// Request approval (may redirect to Auth0 or open a popup)
await signer.requestTransactionSignature({
transaction,
redirectUri: window.location.origin + "/callback",
});
```
The `redirectUri` is where the flow returns after the user approves. Auth0 embeds the encoded transaction in the JWT's `fatxn` claim, which the [NEAR Auth contract](/protocol/contracts/fast-auth) verifies before any signature is produced.
***
## Complete the signing flow
On your callback route, read the approved [signature request](/protocol/concepts/mpc) back out of the provider and turn it into an on-chain `sign` action. That action targets the NEAR Auth contract, which verifies the JWT and asks the MPC network to sign.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
// On the callback page, retrieve the approved request.
// The browser signer returns `{ user, signatureRequest }` — read `.signatureRequest`.
const { signatureRequest } = await signer.getSignatureRequest();
// Build the `sign` call for the NEAR Auth contract
const signAction = await signer.createSignAction(signatureRequest, {
gas: 300000000000000n,
deposit: 1n,
});
// Add `signAction` to a transaction sent to the NEAR Auth contract.
// The contract verifies the JWT and returns an MPC signature.
```
`createSignAction` wraps a `sign` function call with `guard_id`, `verify_payload`, `sign_payload`, and `algorithm` taken from the signature request — the exact arguments the contract's `sign` method expects. `gas` defaults to `300000000000000n` and `deposit` to `0n` if you omit the options. See [the NEAR Auth contract](/protocol/contracts/fast-auth) for how this call is processed.
The React SDK offers one-call convenience methods that do the request, retrieve, and submit steps for you — see [Relayer-backed convenience methods](#relayer-backed-convenience-methods-react) below.
***
## Delegate actions for gasless transactions
A delegate action is a signed intent that a [relayer](/protocol/concepts/relayer) wraps in a meta-transaction and submits — paying the gas so your users can transact without holding NEAR. Build a `DelegateAction` and request a signature the same way you would a transaction.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { buildDelegateAction } from "near-api-js/lib/transaction";
import { transactions } from "near-api-js";
const publicKey = await signer.getPublicKey();
const delegateAction = buildDelegateAction({
senderId: "sender.near",
receiverId: "receiver.near",
actions: [
transactions.transfer(BigInt("1000000000000000000000000")),
],
publicKey,
nonce,
maxBlockHeight,
});
// Request approval for the delegate action
await signer.requestDelegateActionSignature({
delegateAction,
redirectUri: window.location.origin + "/callback",
});
```
Once the user approves, you retrieve the signature request with `getSignatureRequest()` (read `.signatureRequest` off the result) and hand the signed delegate action to a relayer. The relayer wraps it in a [meta-transaction](https://docs.near.org/protocol/transactions/meta-tx) and submits it, covering the gas so nothing is charged to the end user. Read more about how submission works on the [relayer concept page](/protocol/concepts/relayer).
***
## Relayer-backed convenience methods (React)
The React SDK's signer bundles a relayer, so you can request approval and submit in a single call. `signAndSendTransaction` and `signAndSendDelegateAction` handle the request, retrieve the signature request, relay it, and return the final execution outcome.
```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { useSigner } from "@fast-auth-near/react-sdk";
function SendButton({ transaction }) {
const { signer } = useSigner();
const send = async () => {
if (!signer) return;
// Sign and submit a transaction through the relayer
const outcome = await signer.signAndSendTransaction({
transaction,
redirectUri: window.location.origin + "/callback",
});
// Or sign and submit a gasless delegate action
// const outcome = await signer.signAndSendDelegateAction({
// delegateAction,
// receiverId: "receiver.near",
// redirectUri: window.location.origin + "/callback",
// });
};
return ;
}
```
Both methods default to the `eddsa` MPC algorithm; pass `algorithm` to override. Because they relay the transaction for you, they return a `FinalExecutionOutcome` rather than an action you have to submit yourself.
These convenience methods are specific to the React SDK. With the framework-agnostic Browser SDK you assemble and submit the transaction yourself using `createSignAction` and your own relayer or RPC connection.
***
## Get the user's public key
Every identity deterministically derives its own NEAR key through the MPC network. Fetch it to build transactions or create an account for the user. `getPublicKey` defaults to `ed25519`; pass an algorithm to derive a different curve.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Ed25519 public key (default)
const publicKey = await signer.getPublicKey();
// Or specify an algorithm
const secp256k1Key = await signer.getPublicKey("secp256k1");
```
Under the hood this queries the MPC contract's `derived_public_key` view at the user's authentication path, so the same login always resolves to the same NEAR account.
***
## Next steps
How distributed key shares produce a signature without ever assembling a private key.
How a relayer wraps delegate actions in meta-transactions and sponsors gas.
How the on-chain contract verifies the JWT and requests the MPC signature.
Log users in and manage sessions before requesting signatures.
# Quickstart
Source: https://docs.auth.near.org/home/quickstart
Go from zero to a signed NEAR transaction on mainnet — install, log in, and sign in a handful of lines.
This is the fastest path from an empty project to a signed NEAR transaction. You'll install a NEAR Auth SDK, wire up the Auth0 provider on **mainnet**, log a user in, read their derived public key, and request a signature for a simple transfer.
Mainnet requires approved credentials, so [apply for access](/home/apply) to get your Auth0 client id before shipping.
Everything on this page uses the **Auth0** login path on **mainnet**. Use the Auth0 client id you receive after [applying](/home/apply), the NEAR Auth contract lives at `fast-auth.near`, and the MPC signer is `v1.signer`.
Building locally? You can develop against testnet using the values in [Resources → Testnet](/resources/testnet).
Pick your stack and follow the steps.
Add the React SDK, the JavaScript (Auth0) provider, and `near-api-js`.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/react-sdk @fast-auth-near/javascript-provider near-api-js
```
Create a `JavascriptProvider` for `mainnet` with your client id, connect to the mainnet RPC, and wrap your app in `FastAuthProvider`. The provider fills in the correct Auth0 domain and signing audience for mainnet automatically.
```tsx App.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthProvider } from "@fast-auth-near/react-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
import { connect } from "near-api-js";
const provider = new JavascriptProvider({
network: "mainnet",
clientId: "",
});
const { connection } = await connect({
networkId: "mainnet",
nodeUrl: "https://rpc.mainnet.near.org",
});
export default function App() {
return (
);
}
```
`FastAuthProvider` builds a relayer-aware `FastAuthClient` under the hood, pointed at `fast-auth.near` and `v1.signer`. You reach it through the hooks below.
Grab the client with `useFastAuth`, check status with `useIsLoggedIn`, and call `login()` to open the Auth0 flow.
```tsx LoginButton.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { useFastAuth, useIsLoggedIn } from "@fast-auth-near/react-sdk";
function LoginButton() {
const { client } = useFastAuth();
const { isLoggedIn } = useIsLoggedIn();
if (isLoggedIn) return You're signed in 🎉;
return ;
}
```
Once the user is authenticated, obtain a signer and read the NEAR public key derived for their identity. The `usePublicKey` hook returns the key directly, or you can pull a signer yourself with `useSigner`.
```tsx AccountInfo.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { useSigner, usePublicKey } from "@fast-auth-near/react-sdk";
function AccountInfo() {
const { signer } = useSigner();
const { publicKey } = usePublicKey();
return {publicKey?.toString()};
}
```
The derived key is deterministic — the same Auth0 login always controls the same NEAR key. `getPublicKey()` returns an Ed25519 key by default; pass `"secp256k1"` if you need that curve.
Build a transfer, request the signature (this triggers an Auth0 approval), then let the relayer-backed signer submit it. In the React SDK the signer exposes `signAndSendTransaction`, which requests the signature, calls the NEAR Auth contract, and broadcasts the result for you.
```tsx Transfer.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { transactions } from "near-api-js";
import { useSigner, usePublicKey } from "@fast-auth-near/react-sdk";
function Transfer({ senderId, nonce, blockHash }) {
const { signer } = useSigner();
const { publicKey } = usePublicKey();
async function transfer() {
const transaction = transactions.createTransaction(
senderId, // sender account id
publicKey, // sender's derived public key
"receiver.near", // receiver
nonce, // account nonce
[transactions.transfer(BigInt("1000000000000000000000000"))], // 1 NEAR
blockHash, // recent block hash
);
// Requests the Auth0 signature, submits to fast-auth.near,
// and broadcasts via the relayer.
const result = await signer.signAndSendTransaction({ transaction });
console.log(result.transaction.hash);
}
return ;
}
```
Requesting a signature performs an **Auth0 context switch** — a popup or a full-page redirect, depending on how you configure the provider. Design your UX to expect it: persist any in-flight state before the call, and handle the return so users land back where they started. On redirect, the signature is retrieved on the callback page.
Add the framework-agnostic Browser SDK, the JavaScript (Auth0) provider, and `near-api-js`.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/browser-sdk @fast-auth-near/javascript-provider near-api-js
```
Create a `JavascriptProvider` for `mainnet`, connect to the mainnet RPC, and build a `FastAuthClient` pointed at the mainnet NEAR Auth and MPC contracts.
```ts main.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthClient } from "@fast-auth-near/browser-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
import { connect } from "near-api-js";
const provider = new JavascriptProvider({
network: "mainnet",
clientId: "",
});
const { connection } = await connect({
networkId: "mainnet",
nodeUrl: "https://rpc.mainnet.near.org",
});
const client = new FastAuthClient(provider, connection, {
fastAuthContractId: "fast-auth.near",
mpcContractId: "v1.signer",
});
```
Kick off the Auth0 login. You can check status any time with the provider's `isLoggedIn()`.
```ts login.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
await client.login();
const loggedIn = await provider.isLoggedIn();
if (loggedIn) console.log("Authenticated!");
```
Obtain a signer and read the derived NEAR public key. `getPublicKey()` returns Ed25519 by default; pass `"secp256k1"` for that curve.
```ts signer.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
const signer = await client.getSigner();
const publicKey = await signer.getPublicKey();
console.log(publicKey.toString());
```
The key is derived deterministically from the user's identity, so the same login always maps to the same NEAR key.
Build a transfer, request the signature (this triggers an Auth0 approval), then retrieve the signature request, turn it into a sign action for the NEAR Auth contract, and have a relayer submit it.
```ts transfer.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { transactions } from "near-api-js";
// 1. Build the transaction.
const transaction = transactions.createTransaction(
senderId, // sender account id
publicKey, // sender's derived public key
"receiver.near", // receiver
nonce, // account nonce
[transactions.transfer(BigInt("1000000000000000000000000"))], // 1 NEAR
blockHash, // recent block hash
);
// 2. Request the signature (Auth0 popup or redirect).
await signer.requestTransactionSignature({ transaction });
// 3. On return, read the signature request and build the sign action.
const { signatureRequest } = await signer.getSignatureRequest();
const action = await signer.createSignAction(signatureRequest, {
deposit: 1n,
});
// 4. A relayer submits `action` to fast-auth.near, which verifies
// the Auth0 JWT and returns the MPC signature. The relayer then
// broadcasts the signed transaction.
```
`requestTransactionSignature` performs an **Auth0 context switch** — a popup or a full-page redirect. Design your UX to expect it: persist in-flight state before the call, and on redirect read the signature back on the callback page with `getSignatureRequest()`.
The relayer is what submits `action` to `fast-auth.near` and broadcasts the result — optionally sponsoring gas via a delegate action so users transact without holding NEAR. See [Sign transactions](/home/guides/sign-transactions) for the full relayer round-trip.
Add the React Native provider alongside `react-native-auth0`, which it uses under the hood for the native Auth0 flow.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/react-native-provider react-native-auth0
```
Wrap your app in `Auth0Provider` with the mainnet domain, and create a `ReactNativeProvider` for `mainnet` with your client id.
```tsx App.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { Auth0Provider } from "react-native-auth0";
import { ReactNativeProvider } from "@fast-auth-near/react-native-provider";
const provider = new ReactNativeProvider({
network: "mainnet",
clientId: "",
});
export default function App() {
return (
);
}
```
On mobile you drive login and signature requests through the provider. To read keys and submit transactions, pair the provider with the Browser SDK's `FastAuthClient` and a mainnet NEAR connection (`https://rpc.mainnet.near.org`), configured with `fastAuthContractId: "fast-auth.near"` and `mpcContractId: "v1.signer"` — exactly as in the Browser / JS tab.
Trigger the native Auth0 login from anywhere in your component tree.
```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
await provider.login();
```
Build a `FastAuthClient` with the provider and a mainnet connection, then read the derived public key.
```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthClient } from "@fast-auth-near/browser-sdk";
import { connect } from "near-api-js";
const { connection } = await connect({
networkId: "mainnet",
nodeUrl: "https://rpc.mainnet.near.org",
});
const client = new FastAuthClient(provider, connection, {
fastAuthContractId: "fast-auth.near",
mpcContractId: "v1.signer",
});
const signer = await client.getSigner();
const publicKey = await signer.getPublicKey();
console.log(publicKey.toString());
```
Request the transfer signature, read the signature request, and turn it into a sign action for the NEAR Auth contract. A relayer then submits it to `fast-auth.near`.
```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
await provider.requestTransactionSignature({ transaction });
const { signatureRequest } = await signer.getSignatureRequest();
const action = await signer.createSignAction(signatureRequest, {
deposit: 1n,
});
// A relayer submits `action` to fast-auth.near and broadcasts the result.
```
On mobile, a signature request opens the native Auth0 browser session — a **context switch** away from your app. Persist any in-flight state before the call so you can restore it when control returns.
***
## Next steps
You've completed the full loop — login, key derivation, signature, and submission. Go deeper on each part, then take it live.
Login, logout, session checks, and handling the Auth0 popup vs. redirect flows.
The full signature round-trip, delegate actions, and gasless relayer submission.
Apply for approved mainnet credentials to launch your app on `fast-auth.near`.
# What is NEAR Auth
Source: https://docs.auth.near.org/home/what-is
NEAR Auth lets Web2 users sign NEAR transactions with the accounts they already have — no seed phrases, no wallet extensions.
NEAR Auth is an authentication system for NEAR Protocol that lets people sign real on-chain transactions using the identities they already have — Google, Apple, email, or passkeys — instead of a seed phrase or a wallet extension. Logins run through [Auth0](/protocol/concepts/auth0), keys are secured by a Multi-Party Computation (MPC) network, and every signature is gated by an on-chain JWT verification. The result is a Web2 sign-in experience that produces genuine, non-custodial NEAR accounts.
***
## The problem
NEAR's native account model is powerful, but it asks a lot of newcomers. To transact, a user typically has to install a wallet extension, generate and safeguard a seed phrase or full-access key, and fund the account with NEAR before they can do anything. For people arriving from a Web2 product, every one of those steps is a place to drop off — a lost seed phrase means a lost account, and "install this extension" is a hard ask on mobile.
NEAR Auth removes those steps. Users authenticate with a login they already trust, and the cryptography that controls their NEAR account is handled for them — without any single party ever holding their key.
## What it is
NEAR Auth is made of a few cooperating pieces:
* **Auth0 as the identity provider.** Auth0 is the default and primary provider. It handles Google, Apple, Auth0 username/password, and passkey logins, and it embeds the transaction the user is about to sign directly into the JWT it issues.
* **On-chain contracts on NEAR.** The NEAR Auth contract (`FastAuth`) is the entry point. It routes each request to a guard contract that cryptographically verifies the Auth0 JWT — checking the issuer, the audience, and the embedded transaction claim — before any signature is allowed.
* **An MPC network.** A distributed Multi-Party Computation network holds key shares and produces signatures without any single participant ever assembling the full private key. Each identity deterministically derives its own key, so the same login always controls the same NEAR account.
* **Typed SDKs.** Drop-in libraries for web, React, and React Native (the `@fast-auth-near/*` packages) wrap all of this behind a few method calls, so you never touch the contracts or MPC directly.
## Who it's for
NEAR Auth is for teams building consumer-facing NEAR applications who want mainstream users to onboard in seconds:
* **dApp and product teams** who want social login instead of a wallet-connect flow, so first-time users can transact without any Web3 setup.
* **Web and mobile developers** shipping on React, vanilla JavaScript or another framework, or React Native — each has a matching SDK.
* **Anyone who needs non-custodial accounts** without running key infrastructure. Keys live in the MPC network, not in your backend and not in a single vault you have to protect.
## How it works
At a high level, a signed transaction moves through five stages. You call two or three SDK methods; NEAR Auth handles the rest.
The user signs in through Auth0 — Google, Apple, email, or a passkey — using a popup or redirect. Their identity is now established and no seed phrase was ever involved.
When the user wants to act on-chain, your app asks for a signature. Auth0 issues a JWT with the encoded transaction embedded in its `fatxn` claim, binding the login to that exact transaction.
The NEAR Auth contract routes the request to the Auth0 guard, which verifies the JWT on-chain: it confirms the RS256 signature, the issuer and audience, and that the embedded transaction matches what's being signed. No valid JWT, no signature.
Once verification passes, NEAR Auth asks the MPC network to sign at a key path derived deterministically from the user's identity. The signature is produced from distributed key shares — never a reconstructed private key.
The signature comes back to your app, which submits the transaction to NEAR. Optionally, a relayer can submit a delegate action on the user's behalf and sponsor the gas — so users can transact without holding any NEAR.
Auth0 embeds the transaction in the JWT, and the on-chain guard checks that the embedded transaction matches the one being signed. A login can only authorize the exact action the user approved — it can't be replayed to sign something else.
## Key benefits
Users sign in with Google, Apple, email, or passkeys through Auth0 — nothing to install, nothing to write down, nothing to lose.
Keys are never held by a single party. The MPC network produces every signature from distributed key shares, so no one — not even you — can unilaterally sign.
Each identity deterministically derives its own key, so the same login always controls the same NEAR account.
Pair with a relayer to sponsor gas via delegate actions, letting users transact without ever holding NEAR.
Because login runs through Auth0, the experience uses a popup or a full-page redirect back to your app. Design your flow to handle the return — the SDKs restore the session for you, but plan your UI around that round trip.
***
## Next steps
Add social login and sign your first NEAR transaction in under five minutes.
Pick the right library for React, vanilla JavaScript, or React Native.
Go under the hood into the contracts, JWT verification, and MPC signing.
# NEAR Auth
Source: https://docs.auth.near.org/index
Sign NEAR transactions with a Web2 login — no seed phrases, no wallet extensions.
Web2 loginMPC signingNon-custodial
NEAR Auth
Let your users sign NEAR transactions with the accounts they already have — Google, Apple, email, or passkeys — while keys stay secured by a Multi-Party Computation network.
\~5 minReactTypeScript
Add social login to your dApp
Wrap your app in a provider and use hooks to authenticate users and request signatures — no wallet integration required.
Start the quickstart →
Providers, hooks, and the signer API.
Login, logout, and session handling.
```tsx App.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthProvider, useIsLoggedIn, useFastAuth } from "@fast-auth-near/react-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
const provider = new JavascriptProvider({
network: "mainnet",
clientId: "",
});
function LoginButton() {
const { client } = useFastAuth();
const { isLoggedIn } = useIsLoggedIn();
return isLoggedIn
? You're signed in 🎉
: ;
}
export default function App({ connection }) {
return (
);
}
```
\~5 minVanilla JSVueSvelte
Framework-agnostic client
Use the class-based FastAuthClient in any web app to log users in and obtain a signer.
Start the quickstart →
The FastAuthClient and FastAuthSigner classes.
Which library fits your stack.
```tsx App.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { Auth0Provider } from "react-native-auth0";
import { ReactNativeProvider } from "@fast-auth-near/react-native-provider";
const provider = new ReactNativeProvider({
network: "mainnet",
clientId: "",
});
export default function App() {
return (
);
}
// later, inside a component:
await provider.login();
```
***
## Why NEAR Auth
Users sign in with Google, Apple, email, or passkeys through Auth0 — nothing to install, nothing to write down.
Keys are never held by a single party. A Multi-Party Computation network produces every signature from distributed key shares.
Each identity deterministically derives its own key, so the same login always controls the same NEAR account.
A guard contract cryptographically verifies the Auth0 JWT on NEAR before any signature is produced.
Sponsor gas via delegate actions, so users transact without holding NEAR.
Ship on web, React, or React Native with typed SDKs and a handful of lines of code.
***
## Get started in 2 steps
Pick the SDK for your framework and install it alongside the JavaScript (Auth0) provider.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/react-sdk @fast-auth-near/javascript-provider near-api-js
```
Authenticate the user, get a signer, and request a signature for a NEAR transaction.
A complete, copy-pasteable integration in under 5 minutes.
Mainnet requires approved credentials — [apply for production access](/home/apply) to get your Auth0 client ID.
Building locally? You can develop against testnet using the values in [Resources → Testnet](/resources/testnet).
***
## Explore the docs
What NEAR Auth is, quickstarts, integration guides, and going live.
Contracts, JWT verification, the Auth0 flow, MPC signing, and advanced topics.
Reference-style docs for every published library and provider.
Deployed contract addresses and network config.
# Attestation contract
Source: https://docs.auth.near.org/protocol/advanced/attestation
Decentralized, quorum-based public-key management that lets guards source their signing keys without trusting a single admin.
Some guards verify JWTs signed by an issuer whose public keys rotate outside your control — an external OIDC issuer is the canonical example. The **Attestation contract** lets those guards source their trusted public keys from an on-chain, quorum-based process instead of from a single privileged account. Multiple independent attesters must agree on the exact same key set before it becomes active, and only then can a guard read it.
This page explains the on-chain data model, how attesters reach quorum, how a guard consumes the keys, and why this decentralization matters for security.
This is an advanced topic. Guards that back keys with attestation — such as the [custom issuer guard](/protocol/advanced/custom-issuer-guard) — are the primary consumers of this contract. If you are integrating NEAR Auth with the default Auth0 provider, you do not need it.
***
## Why attestation exists
A guard verifies a JWT's RS256 signature against a set of RSA public keys. Whoever controls those keys controls what the guard will accept — so key management is a security-critical surface. There are two ways to feed keys to a guard:
* **Owner-managed keys.** A single admin account writes the keys directly. This is what the Auth0 guard does, and it is simple, but it concentrates trust in one key holder.
* **Attestation-managed keys.** Keys are only accepted once a configurable number of independent attesters submit the *same* key set. No single party can rotate the keys on their own.
The Attestation contract implements the second model. It gives issuers whose keys are outside NEAR Auth's control — like an external OIDC issuer — a trust-minimized way to keep on-chain keys in sync, where compromising key management requires colluding with a quorum of attesters rather than a single admin.
***
## The data model
The contract keeps three pieces of state.
| Field | Type | Description |
| -------------- | ------------------------------------- | ------------------------------------------------------------------ |
| `attestations` | `IterableMap` | The current pending attestation from each attester |
| `quorum` | `u32` | Number of matching attestations required to update the active keys |
| `public_keys` | `Vector` | The currently active public keys guards read |
A public key is an RSA key expressed as its two components:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub struct PublicKey {
n: Vec, // RSA modulus
e: Vec, // RSA exponent
}
```
An attestation is one attester's proposal — the keys they want to install, plus a hash that fingerprints them:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub struct Attestation {
hash: Vec, // SHA256 hash of the public keys
public_keys: Vec, // The attested public keys
}
```
The `hash` is what lets the contract cheaply decide whether two attesters proposed the *same* keys. It is computed by concatenating every key's modulus and exponent bytes in order and hashing the result:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
fn compute_public_keys_hash(&self, public_keys: &[PublicKey]) -> Vec {
let mut data = Vec::new();
for pk in public_keys {
data.extend_from_slice(&pk.n);
data.extend_from_slice(&pk.e);
}
env::sha256(&data).to_vec()
}
```
Because the hash covers both the key bytes and their order, two attesters only match if they agree on the exact same keys arranged the exact same way. Any difference — a rotated key, a reordered list, a single flipped byte — produces a different hash and does not count toward quorum.
***
## Initializing the contract
The contract is initialized once with the quorum and the initial roster of participants:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
#[init]
pub fn new(quorum: u32, super_admins: Vec, attesters: Vec) -> Self
```
The number of attesters that must submit matching keys before the active key set is updated.
Accounts with full administrative privileges. Each is also granted the `DAO` role so it can manage quorum, attesters, pausing, and upgrades.
The initial accounts authorized to submit attestations (granted the `Attester` role).
Initialization enforces three invariants so the contract can never start in an unusable state:
* `quorum` must be greater than `0`.
* There must be at least one super admin.
* `quorum` cannot exceed the number of attesters — otherwise no key set could ever reach quorum.
Access to every mutating method is governed by role-based access control. The roles that matter here are `DAO` (full administrative access, and may also attest) and `Attester` (may submit attestations). The contract also defines operational roles — `CodeStager`, `CodeDeployer`, `DurationManager`, `PauseManager`, and `UnpauseManager` — for staged upgrades and emergency pausing.
***
## Reaching quorum
Attesters install keys by calling `attest_public_keys`. Only accounts holding the `Attester` or `DAO` role may call it, and it is disabled while the contract is paused:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
#[pause]
#[access_control_any(roles(Role::Attester, Role::DAO))]
pub fn attest_public_keys(&mut self, public_keys: Vec)
```
Each call runs the same sequence:
The submitted list must be non-empty, and every key must have a non-empty modulus (`n`) and exponent (`e`).
The contract computes the SHA256 hash of the concatenated key data.
The attestation (hash plus keys) is stored under the caller's account id, replacing any previous attestation from that same attester.
The contract counts how many stored attestations share this hash — that is, how many attesters currently agree on this exact key set.
If the matching count reaches `quorum`, the active `public_keys` are cleared and replaced with the agreed-upon set, and **all** pending attestations are cleared to start the next round fresh.
Because a new call from an attester overwrites their previous proposal, an attester can change their mind by simply re-attesting with different keys — only their latest vote counts.
### Example flow
With a quorum of `2` and three attesters:
1. **Attester A** submits `[PK1, PK2]`. The attestation is stored; the matching count is `1` — below quorum, so nothing changes.
2. **Attester B** submits the same `[PK1, PK2]`. The hash matches A's, the count reaches `2`, quorum is met. The active keys become `[PK1, PK2]` and all attestations are cleared.
3. If **Attester C** had instead submitted a *different* key set, its hash would not match, the count for `[PK1, PK2]` would stay at `1`, and the keys would not update.
Until quorum is reached for the very first time, `public_keys` is empty and any guard reading it gets an empty list — so no signatures can be verified against uninstalled keys.
***
## How a guard reads the keys
A guard consumes attested keys through a single view method:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub fn get_public_keys(&self) -> Vec
```
It returns the currently active key set — the one that most recently reached quorum. A guard that backs its verification with attestation fetches these keys, validates and stores them locally, and then uses them to verify incoming JWT signatures. Concretely, the [custom issuer guard](/protocol/advanced/custom-issuer-guard):
1. Calls `get_public_keys()` on this Attestation contract.
2. Validates the returned keys and stores them.
3. Uses them to verify the RS256 signatures on the issuer's JWTs.
This cleanly separates two concerns: the guard focuses on *authentication* (verifying that a JWT is well-formed and correctly signed), while the Attestation contract owns *key management* (deciding which keys are trusted, and rotating them by consensus).
The contract also exposes read-only helpers for inspecting the process:
| Method | Returns |
| ---------------------------------- | ----------------------------------------------------------------------- |
| `get_public_keys()` | The currently active public keys (empty until quorum is first reached). |
| `get_attestation(account_id)` | The pending attestation from a specific attester, if any. |
| `get_quorum()` | The current quorum threshold. |
| `get_attesters(from_index, limit)` | A paginated list of accounts holding the `Attester` role. |
***
## Managing quorum and attesters
Only accounts with the `DAO` role can adjust the roster or the threshold, and each guarded method preserves the contract's core invariants.
**Change the quorum** with `set_quorum(quorum)`. The new quorum must be greater than `0` and cannot exceed the current number of attesters.
**Add an attester** with `grant_attester(account_id)`, granting them the `Attester` role.
**Remove an attester** with `revoke_attester(account_id)`. This is guarded by a safety check: the revocation is rejected if it would leave fewer attesters than the quorum requires (`quorum >= remaining_attesters`), which would make quorum permanently unreachable. Add more attesters or lower the quorum first.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
// DAO-only, and refuses to strand the contract below quorum
#[pause]
#[access_control_any(roles(Role::DAO))]
pub fn revoke_attester(&mut self, account_id: AccountId)
```
In an emergency the whole contract can be paused. `attest_public_keys`, `set_quorum`, `grant_attester`, and `revoke_attester` are all disabled while paused — accounts with the `PauseManager` or `DAO` role can pause, and `UnpauseManager` or `DAO` can resume. Guards can still read `get_public_keys()`, so verification keeps working against the last-agreed keys while updates are frozen.
***
## Why this matters for security
The value of attestation is that it removes a single point of failure from key management:
* **No unilateral key rotation.** Installing a new key set requires `quorum` independent attesters to submit byte-for-byte identical keys. Compromising one attester is not enough to change what a guard trusts.
* **Tamper-evident agreement.** Because agreement is decided by a SHA256 fingerprint over the exact key bytes and their order, attesters cannot "almost" agree — a mismatched or reordered key silently fails to count, so subtle substitution attacks do not slip through.
* **Recoverable by construction.** The quorum-vs-attester invariants — enforced at init, on `set_quorum`, and on `revoke_attester` — guarantee the contract can never be configured into a state where no key set could ever reach quorum.
* **Clean trust boundary.** Guards trust the outcome of the attestation process, not any individual key holder, so authentication logic and key custody evolve independently.
***
## Next steps
Verify JWTs from your own issuer with attestation-managed keys.
How the NEAR Auth contract, router, and guards fit together.
Bring your own identity provider to NEAR Auth.
# Custom backend integration
Source: https://docs.auth.near.org/protocol/advanced/custom-backend
Run your own off-chain service that participates in the NEAR Auth flow — validating identities and issuing the JWTs a custom guard verifies on-chain.
Most integrations never need a backend: the app authenticates through Auth0, and the Auth0 Guard verifies the resulting JWT entirely on-chain. But when you bring your own identity provider — or need authorization logic that lives off-chain — you can add a **custom backend** that sits between your users and the NEAR Auth contracts. This page explains what that backend does, how it pairs with a custom issuer guard, and the security boundaries you must respect.
Custom backends are an **advanced** topic. If Auth0 covers your use case, start with the [Auth0 flow](/protocol/concepts/auth0) instead — no server of your own is required.
***
## Why add a backend
The NEAR Auth contract verifies JWTs, not user sessions. A guard checks that a token is correctly signed and carries the expected claims, then hands the subject to the MPC network for key derivation. That works out of the box for providers whose keys and issuer the guard already trusts.
A custom backend earns its place when you need to do something the guards can't do alone:
* **Bridge an unsupported provider.** Your users authenticate with an OIDC identity provider (Firebase, a corporate SSO, your own login) that the on-chain guards don't recognise directly.
* **Re-sign under a key you control.** The [Custom Issuer Guard](/protocol/advanced/custom-issuer) trusts JWTs signed by *your* RSA key, not your upstream provider's — so a service must re-issue tokens under that key.
* **Enforce off-chain authorization.** You want rate limiting, allow-lists, business rules, or transaction-level checks *before* a signable token is ever minted.
A custom backend is code you own and operate. You take on the work of validating identities, protecting a signing key, and keeping the service available. Budget for that maintenance before committing to this path.
***
## Where the backend fits
The backend is a **JWT re-signing proxy**. It never touches the NEAR chain and never holds NEAR keys — it validates a token from your identity provider and returns a new token signed with a key that a custom issuer guard already trusts.
```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
┌────────┐ 1. login ┌──────────────────┐
│ User │──────────────▶│ Identity Provider│
└────────┘ │ (e.g. Firebase) │
│ └──────────────────┘
│ 2. provider JWT + sign payload
▼
┌──────────────────┐ 3. re-issued JWT ┌───────────────────────────────┐
│ Custom backend │─────────────────────▶│ FastAuth.sign(guard_id, jwt, │
│ (issuer service) │ │ sign_payload, algorithm) │
└──────────────────┘ └───────────────────────────────┘
│
▼
┌───────────────────────────────┐
│ JWT Guard Router → your guard │
│ RS256-verify → MPC signs at │
│ {guard_id}#{sub} │
└───────────────────────────────┘
```
1. The user signs in with your identity provider and your app receives a provider JWT.
2. The app sends that JWT — plus the transaction it wants signed — to your backend.
3. The backend validates the provider JWT, embeds the transaction, and re-issues a token under your RSA key.
4. The app calls `FastAuth.sign(guard_id, verify_payload, sign_payload, algorithm)` with the re-issued token. The router forwards it to your guard, which RS256-verifies it before the MPC network signs at path `{guard_id}#{sub}`.
The on-chain half of this — the guard, its key management via [Attestation](/protocol/advanced/attestation), and registration in the router — is covered in the [custom issuer guard](/protocol/advanced/custom-issuer) page. The rest of this page focuses on the off-chain service.
***
## The custom issuer service
The repository ships a reference implementation of exactly this backend: a NestJS service under `apps/custom-issuer` in [github.com/Peersyst/fast-auth](https://github.com/Peersyst/fast-auth). It exposes a single endpoint that turns a provider JWT into a token the Custom Issuer Guard accepts.
### The endpoint
```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST /issuer/issue
Content-Type: application/json
{
"jwt": "",
"signPayload": [ /* the transaction/delegate-action bytes to sign */ ]
}
```
```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"token": ""
}
```
The `signPayload` is the encoded transaction (or delegate action) the user wants signed. The service writes it into the re-issued token's `fatxn` claim, which is what binds the JWT to a specific action — exactly the claim the guard checks on-chain.
### What the service does with a request
The token is verified with RS256 against public keys fetched from your provider. For Firebase, the service reads the X.509 certificates from `VALIDATION_PUBLIC_KEY_URL` and refreshes them every five minutes so key rotation is handled automatically.
It requires a non-empty `sub`, checks that `iss` matches the configured `VALIDATION_ISSUER_URL`, and validates the `exp` / `nbf` time claims (unless expiration is explicitly ignored). Any failure returns `401 Unauthorized`.
A fresh JWT is signed with your RSA private key (RS256). It carries the same `sub`, `exp`, and `nbf`, sets `iss` to your service's `ISSUER_URL`, and adds the `fatxn` claim built from `signPayload`.
The re-issued token is what your app passes to `FastAuth.sign()`. Because it is signed with your key and carries your issuer URL, only a guard configured with that key and issuer will verify it.
### Configuration
The service is driven entirely by environment variables:
| Variable | Required | Description |
| --------------------------- | -------- | --------------------------------------------------------------------------------- |
| `KEY_BASE64` | Yes | Base64-encoded RSA private key used to sign re-issued tokens. |
| `VALIDATION_PUBLIC_KEY_URL` | Yes | URL that serves your provider's public keys (e.g. the Firebase certificate URL). |
| `VALIDATION_ISSUER_URL` | Yes | Expected `iss` claim on incoming provider JWTs. |
| `ISSUER_URL` | Yes | The `iss` claim written into re-issued tokens — must match what the guard trusts. |
| `PORT` | No | Server port (default `3000`). |
| `ALLOWED_ORIGINS` | No | Comma-separated CORS origins. |
| `IGNORE_EXPIRATION` | No | Set to `true` to skip `exp`/`nbf` validation. Leave unset in production. |
Generate the RSA key pair the service and guard share:
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Private key for the service to sign with
openssl genrsa -out signing-key.pem 2048
# Public key — its modulus/exponent go into the guard contract
openssl rsa -in signing-key.pem -pubout -out signing-public-key.pem
# Encode the private key for KEY_BASE64
cat signing-key.pem | base64
chmod 600 signing-key.pem
```
Run it locally with `pnpm install && pnpm start:dev` from `apps/custom-issuer`, or build and run the provided Docker image for production. The service also exposes a `/metrics` endpoint (issued vs. failed tokens, request duration) for observability.
***
## Connecting the backend to your guard
The backend and the guard are two halves of one trust relationship: the service signs with a private key, and the guard is configured with the matching public key. The token flows from one to the other.
Set `KEY_BASE64` to the base64-encoded private key and point the validation variables at your identity provider.
Extract the modulus and exponent from your public key and configure the [Custom Issuer Guard](/protocol/advanced/custom-issuer) with them. Because that guard sources keys through [Attestation](/protocol/advanced/attestation), key rotation is a governance action, not a redeploy.
The `ISSUER_URL` your service stamps into tokens must equal the issuer the guard validates. A mismatch here is the most common reason a technically valid token is rejected on-chain.
Add your guard to the JWT Guard Router (or directly to the NEAR Auth contract) under a `guard_id`, then call `FastAuth.sign()` with that id.
The Custom Issuer Guard, unlike the Auth0 Guard, performs **no audience (`aud`) check** — it trusts your service's signature and issuer instead. That is why re-signing under a key you control is the whole point of the backend.
***
## Relaying and gasless transactions
Signing produces a signature; something still has to submit the transaction. A custom backend can take on that role too, either by relaying signed transactions itself or by delegating to a relayer so users transact without holding NEAR.
**Delegate actions are the recommended path for gasless / meta-transactions**, and submitting them requires a relayer — a service that accepts an already-signed payload and broadcasts it, sponsoring gas on the user's behalf. If your backend issues tokens for delegate actions (pass the encoded delegate action as the `signPayload`), the resulting signature can be relayed gaslessly.
For how meta-transactions work and how to run or integrate a relayer, see NEAR's official documentation on [meta-transactions](https://docs.near.org/protocol/transactions/meta-tx). See [the relayer](/protocol/concepts/relayer) for a conceptual overview of how signatures are submitted and how gas sponsorship works.
***
## Security responsibilities
Running a backend means owning the security boundary it creates. Treat these as non-negotiable:
The RSA private key in `KEY_BASE64` is the trust anchor for every token your guard accepts. Store it in a secrets manager, never in client code or version control, and never return it in an API response.
Verify the incoming JWT signature, issuer, and time claims before re-issuing. The reference service enforces a 10 KB request-size limit and strict input validation — keep those guarantees if you fork it.
Serve only over HTTPS and set `ALLOWED_ORIGINS` to the exact origins that may call the service. Do not leave CORS open in production.
A re-signing endpoint is an attractive target. Add rate limiting, watch the failed-token metric, and alert on spikes.
Rotating the signing key means updating both the service (`KEY_BASE64`) and the guard's trusted public keys. Coordinate the two so no valid tokens are rejected mid-rotation.
***
## Next steps
The on-chain half — how the guard verifies your re-issued tokens.
Submit signed transactions and sponsor gas via delegate actions.
Quorum-based management of the public keys your guard trusts.
The full path from login to an on-chain signature.
# Custom issuer service
Source: https://docs.auth.near.org/protocol/advanced/custom-issuer
Run an intermediary JWT issuer that re-signs tokens from Firebase or any OIDC provider so the CustomIssuer Guard can verify them on-chain.
Most NEAR Auth integrations use the Auth0 happy path, where Auth0 issues the JWT and the on-chain [Auth0 Guard](/protocol/contracts/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](/protocol/advanced/custom-issuer-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](/protocol/advanced/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:
The user signs in with Firebase (or your OIDC provider) and your app obtains that provider's JWT.
Your service verifies the token's signature against the provider's public keys and checks its issuer and time claims.
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.
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
```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
┌─────────┐ ┌──────────────────┐ ┌───────────────────┐ ┌──────────────┐
│ User │───▶│ Identity provider│───▶│ Custom issuer │───▶│ NEAR Auth │
│ │ │ (e.g. Firebase) │ │ service │ │ contracts │
└─────────┘ └──────────────────┘ └───────────────────┘ └──────────────┘
│ │
▼ ▼
Issues JWT with Re-issues JWT with
provider's key your signing key
```
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](/protocol/advanced/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.
```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST /issuer/issue
Content-Type: application/json
{
"jwt": "",
"signPayload": [ /* transaction bytes, 0–255 each */ ]
}
```
**Response**
```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"token": ""
}
```
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 (see [`issuer.service.ts`](https://github.com/Peersyst/fast-auth)):
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:
| 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 typed `IssuerConfig`:
```ts issuer.config.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
export type IssuerConfig = {
keyBase64: string;
validationPublicKeyUrl: string;
validationIssuerUrl: string;
issuerUrl: string;
ignoreExpiration: boolean;
};
```
| 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/`). |
| `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. |
`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)
```bash .env theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Base64-encoded RSA private key (cat signing-key.pem | base64)
KEY_BASE64="LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tLi4u"
# Firebase public certificate URL for your service account
VALIDATION_PUBLIC_KEY_URL="https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-xxxxx@your-project.iam.gserviceaccount.com"
# Firebase issuer for your project
VALIDATION_ISSUER_URL="https://securetoken.google.com/your-project-id"
# Your custom issuer URL — must match the guard's configured issuer
ISSUER_URL="https://your-custom-issuer.example.com"
```
### 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.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Private key used by the service
openssl genrsa -out signing-key.pem 2048
# Public key — its modulus/exponent are registered on-chain
openssl rsa -in signing-key.pem -pubout -out signing-public-key.pem
# Base64-encode the private key for KEY_BASE64
cat signing-key.pem | base64
chmod 600 signing-key.pem
```
***
## When to use this path
Reach for the custom issuer service when the Auth0 happy path doesn't fit:
Your users authenticate with Firebase Authentication and you want them signing NEAR transactions without adding Auth0.
You operate a custom OIDC-compliant provider and want to bridge its RS256 tokens into NEAR Auth.
You want full control over the signing keys NEAR Auth trusts, and to manage rotation through attestation.
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](/protocol/concepts/auth0) and [how it works](/protocol/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
The on-chain guard that verifies tokens re-signed by this service.
How your issuer's public key is registered and rotated on-chain.
The RS256 claims — including `fatxn` — that guards verify.
# Custom Issuer Guard
Source: https://docs.auth.near.org/protocol/advanced/custom-issuer-guard
The on-chain guard that verifies JWTs from a custom OIDC issuer using RS256 keys managed by a DAO-governed attestation contract.
The **Custom Issuer Guard** is the on-chain contract that lets NEAR Auth accept JWTs from your own OpenID Connect (OIDC) issuer instead of Auth0. It verifies the RS256 signature, checks the `iss` and `fatxn` claims, and — unlike the [Auth0 Guard](/protocol/contracts/auth0-guard) — performs **no audience (`aud`) check**. Its RSA public keys are not owner-managed; they are pulled from a DAO-governed [Attestation contract](/protocol/advanced/attestation), so keys can rotate dynamically without redeploying the guard.
This is an **advanced** protocol topic. If you are building on the default Auth0 happy path, you do not need this guard — see [How it works](/protocol/how-it-works) instead. Use the Custom Issuer Guard only when you run your own [custom issuer](/protocol/advanced/custom-issuer) service.
The Rust source lives in the [`Peersyst/fast-auth`](https://github.com/Peersyst/fast-auth) repo at `contracts/jwt-guards/custom-issuer-guard`, and the shared verification logic it inherits lives in `contracts/jwt-guards/base-jwt-guard`.
***
## Where it fits
Like every guard, the Custom Issuer Guard implements the shared `JwtGuard` trait and is reached through the router:
The dApp submits `FastAuth.sign(guard_id, verify_payload, sign_payload, algorithm)` on the [NEAR Auth contract](/protocol/contracts/fast-auth), where `guard_id` resolves to your custom-issuer guard and `verify_payload` is the JWT re-issued by your custom issuer.
The [JWT Guard Router](/protocol/contracts/jwt-guard-router) looks up the guard account registered for that `guard_id` and forwards the verification request to this contract.
The Custom Issuer Guard checks the RS256 signature against its stored keys, then validates the issuer and the `fatxn` binding. On success it returns the token subject.
If verification passes, NEAR Auth asks the [MPC network](/protocol/concepts/mpc) to sign at the identity's deterministic path, and a [relayer](/protocol/concepts/relayer) can submit the resulting transaction.
***
## What it verifies
Verification runs through the shared `internal_verify` flow inherited from `base-jwt-guard`, plus the custom-claims check implemented by this guard. A token is accepted only when **all** of the following hold:
| Check | Rule |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Size** | The JWT must not exceed 7 KB (`7168` bytes). |
| **Signature** | The RS256 signature must verify against at least one stored RSA public key, using PKCS#1 v1.5 padding over the `header.payload` segment. |
| **`fatxn`** | The `fatxn` claim (the encoded transaction / delegate-action payload) must byte-for-byte equal the `sign_payload` passed to `sign`. |
| **`exp`** | The token must not be expired (`exp` > current block time in seconds). |
| **`nbf`** | The token must already be valid (`nbf` ≤ current block time), when present. |
| **`iss`** | The `iss` claim must exactly match the `issuer` argument supplied by the caller. |
Unlike the [Auth0 Guard](/protocol/contracts/auth0-guard), the Custom Issuer Guard **does not check the `aud` (audience) claim**. Trust in the token comes from the signature plus the `iss` match, so the RSA keys held by this guard must correspond only to issuers you control. Anyone who can mint a validly signed token for the configured issuer can pass verification.
The custom-claims portion is deliberately minimal — it parses only the `fatxn` field and compares it to the sign payload:
```rust custom-issuer-guard/src/lib.rs theme={"theme":{"light":"github-light","dark":"github-dark"}}
/// Custom claims for a NEAR Auth custom-issuer JWT.
pub struct CustomClaims {
pub fatxn: Vec,
}
// Inside verify_custom_claims:
if claims.fatxn != sign_payload {
return (false, "Transaction payload mismatch".to_string());
}
(true, "".to_string())
```
The `iss`, `exp`, and `nbf` checks (and the RS256 verification itself) are handled by the shared `base-jwt-guard` logic, so this guard only has to bind the token to the exact transaction being signed.
***
## Methods
### `verify`
The public entry point the router calls during a signing request.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub fn verify(
&self,
issuer: String,
jwt: String,
sign_payload: Vec,
predecessor: AccountId,
) -> (bool, String)
```
It delegates to the shared `internal_verify` and returns a tuple of `(verified, message)`. On success, `verified` is `true` and the second element carries the token's `sub` (subject) claim; on failure it is `false` with a human-readable reason such as `"Invalid issuer"`, `"Token expired"`, or `"Transaction payload mismatch"`.
### `set_public_keys`
Refreshes the guard's RSA keys by pulling the current key set from the configured [Attestation contract](/protocol/advanced/attestation). This is the mechanism that enables dynamic key rotation — no redeploy required.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub fn set_public_keys(&mut self) -> Promise
```
It issues a cross-contract call to `get_public_keys()` on the attestation contract, then in the `on_set_public_keys_callback` it validates every returned key with `assert_valid_public_key` and stores them. If the attestation call fails, the callback panics so no partial or invalid key set is ever persisted.
Because keys are sourced from attestation, **anyone** can call `set_public_keys` — it only mirrors what the DAO-governed attestation contract already publishes. Governance of which keys are trusted lives in the attestation contract, not here.
### `set_attestation_contract` and `get_attestation_contract`
Point the guard at a different attestation contract, or read the one currently configured.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
#[access_control_any(roles(Role::DAO))]
pub fn set_attestation_contract(&mut self, attestation_contract: AccountId)
pub fn get_attestation_contract(&self) -> AccountId
```
Changing the attestation source is a privileged operation restricted to the `DAO` role; reading it is open.
### `get_public_keys`
The `JwtGuard` trait accessor that returns the RSA public keys the guard currently trusts.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
fn get_public_keys(&self) -> Vec
```
Each `JwtPublicKey` is the RSA modulus (`n`) and exponent (`e`) as byte vectors — 2048-bit PKCS#1 v1.5 keys.
***
## Roles and access control
The guard uses the `near-plugins` access-control and upgradable framework. Four roles govern administration and staged upgrades:
| Role | Responsibility |
| ----------------- | --------------------------------------------------------------------------------------------------------- |
| `DAO` | Super-administrative role. Can repoint the attestation contract and holds every upgrade permission below. |
| `CodeStager` | Can stage new contract code ahead of a deployment. |
| `CodeDeployer` | Can deploy staged code updates. |
| `DurationManager` | Can initialize and update the upgrade timelock (duration) settings. |
Upgrades are staged and time-locked: the `code_stagers`, `code_deployers`, and the duration initializer/updater/applier permissions are each granted to the relevant role **and** to `DAO`, so the DAO can always act as a backstop. Roles are seeded at initialization from a `RolesConfig` of `super_admins`, `admins`, and `grantees`, alongside the initial `public_keys`.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
#[init]
pub fn init(config: CustomIssuerGuardConfig, attestation_contract: AccountId) -> Self
```
`CustomIssuerGuardConfig` carries the starting `public_keys` and the `roles` configuration; the attestation contract account is passed separately and can later be changed by the `DAO`.
***
## How it differs from the Auth0 Guard
Auth0 Guard requires `aud` to contain its own account id. The Custom Issuer Guard performs **no** audience check.
Auth0 Guard keys are owner-managed. Custom Issuer Guard keys are pulled from a DAO-governed attestation contract and rotate dynamically.
Auth0 Guard trusts Auth0's issuer. This guard trusts whatever `iss` you supply, backed by keys you attest to.
Auth0 Guard is single-owner. This guard is role-based (`DAO` and upgrade roles) with staged, time-locked upgrades.
Everything else — the RS256 signature check, the 7 KB size limit, the `fatxn`-to-`sign_payload` binding, and the `exp`/`nbf`/`iss` validation — is shared with the other guards through `base-jwt-guard`.
***
## Next steps
Run your own OIDC issuer service that mints the JWTs this guard verifies.
The DAO-governed contract that publishes the RSA keys the guard fetches.
How signing requests are routed to the right guard.
The default guard, and the audience-checking counterpart to this one.
# Auth0 integration
Source: https://docs.auth.near.org/protocol/concepts/auth0
How NEAR Auth uses Auth0 as its default identity provider to authenticate users and authorize every transaction.
NEAR Auth uses [Auth0](https://auth0.com/) as its **primary, default identity provider**. Auth0 handles the login experience across many familiar methods, and — crucially — it re-authenticates the user for **every transaction**, embedding the transaction itself inside the JWT it issues. That JWT is later verified on-chain by the [Auth0 Guard](/protocol/contracts/auth0-guard) before any signature is produced.
Auth0 is the default provider for the whole product. Unless you configure a custom issuer, every login and every signature request in NEAR Auth flows through Auth0.
***
## Supported login methods
Through Auth0, NEAR Auth supports several ways for users to sign in — no seed phrases and nothing to install:
Users sign in with their existing Google account. No new credentials to create.
Apple Sign-In for a secure, privacy-preserving login on iOS and beyond.
Auth0's native email/password authentication for users who prefer a dedicated account.
Passwordless, public-key authentication bound to the user's device.
Each of these resolves to the same thing under the hood: a stable user identifier (the JWT `sub` claim) that deterministically maps to one NEAR key. The same login always controls the same account, regardless of which method the user picked.
***
## Per-transaction authentication
NEAR Auth does not just authenticate users once at login. For **every transaction or delegate action**, the app asks Auth0 to issue a fresh JWT whose payload contains the encoded transaction. This means each sensitive operation is individually authorized by the user.
The mechanism is a custom JWT claim called **`fatxn`**. When you request a signature, the provider Base64-encodes the transaction (or delegate action) and passes it to Auth0 as an authorization parameter. Auth0 mints a JWT that carries the encoded payload in `fatxn`, alongside the standard claims (`sub`, `iss`, `exp`, `aud`, …).
On-chain, the [Auth0 Guard](/protocol/contracts/auth0-guard) verifies the JWT's RS256 signature and issuer, then checks that its `fatxn` claim **matches the transaction being signed**. If they don't match, verification fails and no signature is produced — so a JWT issued for one transaction can never be replayed to sign a different one.
Your app calls `requestTransactionSignature({ transaction })` (or `requestDelegateActionSignature({ delegateAction })`) on the provider.
The provider encodes the transaction and sends it to Auth0 with the `transaction:sign` scope and the network's `signingAudience`. Auth0 returns a JWT whose `fatxn` claim holds the encoded transaction.
The Auth0 Guard checks the JWT's signature, `iss`, `aud`, and that `fatxn` equals the payload being signed — then the MPC network produces the signature.
To retrieve the request afterward, call `getSignatureRequest()`. It fetches the token silently for the `signingAudience`, decodes the `fatxn` claim, and returns a `SignatureRequest` of `{ guardId, verifyPayload, signPayload }` ready to hand to the NEAR Auth contract.
Read more about the token structure and claims in [JWT verification](/protocol/concepts/jwt).
***
## Login: popup vs. redirect
The [JavaScript provider](/sdks/javascript-provider) supports two Auth0 flows, and it picks one based on the options you pass:
* **Popup** (default) — call `login()` with no `redirectUri`. Auth0 opens in a popup window and control returns to your page when the user finishes. This keeps your app's state intact and is the smoothest experience for single-page apps.
* **Redirect** — call `login({ redirectUri })` with a `redirectUri`. The browser navigates away to Auth0 and returns to your callback URL. The provider detects the `code`/`state` query parameters on return and completes the login automatically.
The same choice applies to signature requests: `requestTransactionSignature({ transaction, redirectUri })` uses redirect when a `redirectUri` is present, and popup otherwise.
```ts popup.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
const provider = new JavascriptProvider({
network: "testnet",
clientId: "your-auth0-client-id",
});
// Popup: no redirectUri
await provider.login();
// Force the account picker on the next login
await provider.login({}, true);
```
```ts redirect.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
const provider = new JavascriptProvider({
network: "testnet",
clientId: "your-auth0-client-id",
});
// Redirect: pass a redirectUri to send the user to Auth0 and back
await provider.login({ redirectUri: "https://yourapp.com/callback" });
// On the callback page, isLoggedIn() completes the redirect handshake
const signedIn = await provider.isLoggedIn();
```
With the redirect flow the browser leaves your app and returns to `redirectUri`, so any in-memory state is lost across the round trip. Make sure your callback page reconstructs the state it needs, or prefer the popup flow for single-page apps.
***
## Configuration and network defaults
You configure the JavaScript provider with a small options object:
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
new JavascriptProvider({
network: "mainnet" | "testnet",
clientId: string,
domain?: string, // optional — defaults per network
signingAudience?: string, // optional — defaults per network
});
```
* **`network`** selects mainnet or testnet and picks the default `domain` and `signingAudience`.
* **`clientId`** is your Auth0 application client id.
* **`domain`** is the Auth0 tenant that issues tokens.
* **`signingAudience`** is the Auth0 API audience used specifically for **signature requests**. It is what routes a signing JWT to the Auth0 Guard: the audience value is the guard's on-chain account id, and the guard verifies that its own account appears in the token's `aud` claim.
If you leave `domain` and `signingAudience` unset, NEAR Auth fills them in from `FAST_AUTH_AUTH0_DEFAULTS` for your network:
| Network | `domain` | `signingAudience` | `clientId` |
| ----------- | ----------------------------- | ----------------------------- | ---------------------------------- |
| **mainnet** | `login.auth.near.org` | `auth0.jwt.fast-auth.near` | `dsurLc47fOcWme5PkYeClBvuW0tYrmgW` |
| **testnet** | `login.testnet.fast-auth.com` | `auth0.jwt.fast-auth.testnet` | `np8paqIpMWmNbzT4xAvOOapZBjsOpptl` |
The `signingAudience` values (`auth0.jwt.fast-auth.near` / `auth0.jwt.fast-auth.testnet`) are the **Auth0 Guard contract accounts**. Requiring the guard's own account in `aud` is how the Auth0 Guard ensures a token was minted for it and not for some other consumer.
The guard identifier the provider produces from these values takes the form `jwt#https:///`, and the MPC derivation path is `jwt#https:///#` — deterministic per user identity.
***
## Where this fits
Auth0 is one layer of the NEAR Auth protocol: it authenticates users and authorizes transactions off-chain, while a guard contract enforces those tokens on-chain and the MPC network signs.
The on-chain contract that RS256-verifies Auth0 JWTs and checks the `fatxn` claim.
The token format, standard claims, and the custom `fatxn` payload.
The web provider that drives Auth0 login and signature requests.
The end-to-end flow from login to on-chain signature.
# JWT verification
Source: https://docs.auth.near.org/protocol/concepts/jwt
How NEAR Auth structures JWTs and verifies their signatures and claims entirely on-chain.
Every signature NEAR Auth produces starts with a JSON Web Token (JWT). The identity provider — Auth0 by default — issues a signed JWT that carries both the user's identity and the exact transaction they want to sign. A guard contract on NEAR then verifies that token's signature and claims **on-chain**, so no off-chain server needs to be trusted to authorize the operation.
This page explains how those JWTs are shaped and exactly how the guard verifies them.
***
## JWT anatomy
A JWT is three Base64URL-encoded segments joined by dots:
```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
header.payload.signature
```
* **header** — algorithm and key metadata. NEAR Auth's guards expect `alg: "RS256"` and use the `kid` (key id) to identify which signing key was used.
* **payload** — the JSON claims describing the user and the request (see below).
* **signature** — an RSA signature over the ASCII string `header.payload` (the first two segments, dots included, exactly as they appear in the token).
The signed message is the concatenation of the encoded header and payload. The guard reconstructs it verbatim before checking the signature:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
let (header, payload, signature) = decode_jwt(jwt);
// The data that was signed is header + "." + payload
let data_to_verify = format!("{header}.{payload}");
```
Tokens are capped at **7168 bytes (7 KB)**. A JWT larger than that is rejected before any cryptography runs, which bounds gas usage and guards against oversized-input abuse.
***
## The claims
The guard deserializes the payload into a small, strict set of standard claims:
| Claim | Type | Meaning |
| ----- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sub` | string | Subject — the stable, unique identifier for the authenticated user. Must be non-empty; it becomes the identity component of the MPC derivation path. |
| `iss` | string | Issuer — the identity provider that minted the token. Must match the issuer the guard is configured for. |
| `exp` | number | Expiry, as a UNIX timestamp in seconds. The token is rejected once the current block time passes it. |
| `nbf` | number (optional) | Not-before, as a UNIX timestamp in seconds. The token is rejected while the current block time is still below it. |
| `aud` | string or array | Audience — who the token is intended for. Used by the Auth0 guard (see custom claims). |
### The `fatxn` claim
Alongside the standard claims, NEAR Auth relies on one custom claim:
The encoded transaction or delegate action the user is authorizing, embedded into the JWT at login-to-sign time.
The `fatxn` claim is what binds a token to a specific action. When a user requests a signature, the provider asks the identity provider to mint a JWT whose `fatxn` claim is the Borsh-encoded transaction (or delegate action) payload. Because `fatxn` is signed as part of the token, an attacker cannot swap in a different transaction after the fact — the RSA signature would no longer verify.
The guard compares `fatxn` against the `sign_payload` passed into the on-chain call. Only if they are byte-for-byte identical does verification proceed, guaranteeing that the transaction the MPC network signs is exactly the one the identity provider attested to.
***
## On-chain verification
Guards implement a shared `JwtGuard` trait whose `internal_verify` routine runs the full check in two phases: first the RSA signature, then the claims. If either phase fails, the whole verification fails and no signature is ever produced.
Reject the token immediately if it exceeds the 7 KB limit.
Recompute `header.payload`, then verify the RSA signature against every configured public key. If **any** key validates the signature, the token's signature is accepted.
Parse the payload into claims and check `exp`, `nbf`, and `iss`.
Run the guard-specific checks — for the Auth0 guard, that's the `aud` and `fatxn` checks.
### RS256 signature check
`RS256` means **RSASSA-PKCS1-v1\_5 with SHA-256**. The guard verifies it from raw key components — the modulus `n` and exponent `e` — using 2048-bit keys:
1. Hash the signed message with **SHA-256**.
2. Interpret the signature, `n`, and `e` as big integers at 2048-bit precision.
3. Reject the signature up front unless it is strictly less than the modulus `n`.
4. Recover the padded message by computing `signature^e mod n` via square-and-multiply modular exponentiation.
5. Validate the recovered bytes against the **PKCS#1 v1.5** layout — `0x00 || 0x01 || PS || 0x00 || DigestInfo || Hash`, where `PS` is at least eight `0xFF` bytes — and confirm the trailing hash equals the SHA-256 digest from step 1.
Padding and hash comparisons use constant-time equality, and the function returns only a boolean — never a detailed error — so verification leaks no oracle about *why* a bad signature failed.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Simplified: verify the SHA-256 / PKCS#1 v1.5 signature from key components
pub fn verify_signature_from_components(
payload: String, // "header.payload"
signature_bytes: Vec,
n: Vec, // RSA modulus
e: Vec, // RSA exponent
) -> bool;
```
Because a token may have been signed by any of the provider's rotating keys, the guard tries **every configured public key** and accepts the token if a single one validates:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
let public_keys = self.get_public_keys();
public_keys.into_iter().any(|public_key| {
verify_signature_from_components(
data_to_verify.clone(),
signature_bytes.clone(),
public_key.n.clone(),
public_key.e.clone(),
)
})
```
### The public key struct
Each configured key is stored as its raw big-endian RSA components:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub struct JwtPublicKey {
pub n: Vec, // modulus (2048-bit)
pub e: Vec, // exponent (commonly 65537, i.e. [0x01, 0x00, 0x01])
}
```
How these keys get on-chain and who is allowed to change them differs by guard. The Auth0 guard keeps an owner-managed key set; other guards source their keys from the attestation system. See [the Auth0 guard](/protocol/contracts/auth0-guard) for the Auth0 case.
### Standard claim checks
Once the signature is trusted, the guard validates the claims against the current block time (`block_timestamp_ms` converted to seconds):
* **Expiry** — fails with `Token expired` if `exp` is at or before now.
* **Not-before** — fails with `Token not yet valid` if `nbf` is in the future.
* **Issuer** — fails with `Invalid issuer` if `iss` does not match the guard's configured issuer.
On success the guard returns the `sub` claim, which the NEAR Auth contract uses to derive the user's MPC key.
### Guard-specific custom claims
Standard claim checks are common to all guards, but each guard also enforces its own custom claims before the standard ones. For the **Auth0 guard** this means:
* **`aud`** — the token's audience must contain the guard's own account id, so a token minted for a different audience can't be replayed against it.
* **`fatxn`** — the embedded transaction payload must exactly equal the `sign_payload` supplied to the on-chain call.
Other guards vary these rules — for example, a custom-issuer guard skips the audience check. The `fatxn` binding, however, is universal: a guard never authorizes a transaction it wasn't explicitly presented with.
***
## Next steps
How Auth0 issues the JWTs NEAR Auth verifies, and which login methods it supports.
The on-chain contract that runs this verification and manages its RSA keys.
# MPC signing
Source: https://docs.auth.near.org/protocol/concepts/mpc
How NEAR Auth derives per-user keys and produces signatures through a distributed Multi-Party Computation network — no single party ever holds a full private key.
NEAR Auth never stores a private key. Instead, it relies on a **Multi-Party Computation (MPC)** network to derive a unique key for every authenticated identity and to produce signatures collaboratively. The full private key is split into shares held by independent parties, and no single participant — including the NEAR Auth contract — can ever reconstruct it. This page explains how the MPC integration works: the derivation path, the supported signature algorithms, the on-chain configuration, and the end-to-end signing flow.
This is the last hop of the protocol. Before MPC ever signs, a guard contract must cryptographically verify the user's JWT. See [the NEAR Auth contract](/protocol/contracts/fast-auth) for how verification and signing are chained together in a single call.
***
## What MPC provides
NEAR Auth uses the NEAR MPC network to deliver three properties that make Web2 login safe for controlling on-chain funds:
Each authenticated identity deterministically derives its own key pair. The same login always controls the same account.
Signatures are produced from distributed key shares. No party — not even the contract — ever sees the full private key.
The MPC can sign for many chains (NEAR, Ethereum, Bitcoin, and more) because the derivation and signing are curve-based, not NEAR-specific.
***
## The derivation path
When a user authenticates, NEAR Auth constructs a deterministic signing path from two pieces: the **guard id** that verified the identity and the **subject** returned by that guard.
```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
{guard_id}#{user_subject}
```
The MPC uses this path to derive a unique key pair. Because the path is deterministic, the guarantees fall out naturally:
* **Different identities get different keys** — the subject is part of the path.
* **The same identity always gets the same key** — deriving twice yields the same key pair.
* **Keys are isolated between providers** — the guard id namespaces every identity, so an Auth0 user and a custom-issuer user with the same subject never collide.
Some example paths:
| Path | Meaning |
| -------------------------------------- | ----------------------------------------------------- |
| `jwt#auth0#google-oauth2\|123456789` | An Auth0 user who signed in with Google. |
| `jwt#auth0#email\|abcdef123456` | An Auth0 user who signed in with email. |
| `jwt##user@example.com` | A custom-issuer user (an advanced, non-Auth0 issuer). |
The NEAR Auth contract splits the guard id on `#` to find the guard prefix, so guard ids themselves may not contain `#` — that separator is reserved for building the path. The subject returned by the guard is also validated on-chain: it must not contain `#` and must be at most 256 characters.
***
## Signature algorithms
The NEAR Auth contract supports three signature algorithms, selected by the `algorithm` argument to `sign` — `"secp256k1"`, `"ecdsa"`, or `"eddsa"` (case-insensitive). The algorithm determines which MPC request format and which MPC contract interface is used.
The legacy path uses the original `SignRequest` format against the legacy MPC interface. The payload is the raw SHA-256 hash of the data to sign, and the request carries the configured MPC **key version**.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub struct SignRequest {
pub payload: Vec, // SHA-256 hash of the data to sign
pub path: String, // {guard_id}#{user_subject}
pub key_version: u32, // mpc_key_version
}
```
ECDSA uses the newer `SignRequestV2` format. The SHA-256 hash of the payload is hex-encoded and wrapped in the `Ecdsa` variant of `PayloadType`, and the request carries the configured **domain id**.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub enum PayloadType {
Ecdsa(String), // hex-encoded SHA-256 hash
Eddsa(String),
}
pub struct SignRequestV2 {
pub path: String, // {guard_id}#{user_subject}
pub payload_v2: PayloadType, // PayloadType::Ecdsa(hex_payload)
pub domain_id: u64, // mpc_domain_id
}
```
EdDSA also uses `SignRequestV2`, with the hex-encoded SHA-256 hash wrapped in the `Eddsa` variant of `PayloadType` and the configured **domain id**.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub struct SignRequestV2 {
pub path: String, // {guard_id}#{user_subject}
pub payload_v2: PayloadType, // PayloadType::Eddsa(hex_payload)
pub domain_id: u64, // mpc_domain_id
}
```
Both `SignRequestV2` variants target the current MPC interface, while `secp256k1` targets the legacy interface. In all three cases the request `path` is the `{guard_id}#{user_subject}` derivation path described above.
***
## MPC configuration
The NEAR Auth contract stores the MPC parameters in its own state so they can be updated without redeploying. Each has a sensible default.
| Setting | Description | Default |
| ----------------- | --------------------------------------------------------------------------------- | ------------------------------ |
| `mpc_address` | Account id of the MPC contract that receives sign requests. | The contract's own account id. |
| `mpc_key_version` | Key version used in the legacy `secp256k1` `SignRequest` (supports key rotation). | `0` |
| `mpc_domain_id` | Domain id used in `SignRequestV2` for `ecdsa` / `eddsa`. | `1` |
Each value has a public getter and an owner-only setter. The setters also require the contract to be unpaused:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Getters (view)
pub fn mpc_address(&self) -> AccountId
pub fn mpc_key_version(&self) -> u32
pub fn mpc_domain_id(&self) -> u64
// Setters (owner only)
pub fn set_mpc_address(&mut self, mpc_address: AccountId)
pub fn set_mpc_key_version(&mut self, mpc_key_version: u32)
pub fn set_mpc_domain_id(&mut self, mpc_domain_id: u64)
```
On the deployed networks, `mpc_address` points at the NEAR MPC signer — `v1.signer` on mainnet and `v1.signer-prod.testnet` on testnet. See [Resources](/resources/mainnet) for the full list of deployed addresses.
***
## The signing flow
A single call to `FastAuth.sign` chains JWT verification and MPC signing together. From the caller's perspective it is one request; on-chain it is a promise chain across the guard and the MPC contract.
The caller invokes `FastAuth.sign(guard_id, verify_payload, sign_payload, algorithm)`, attaching a deposit to cover MPC costs. The contract validates that `algorithm` is one of the supported values before doing anything else.
NEAR Auth resolves the guard from the `guard_id` prefix and calls its `verify` method. The guard checks the JWT and returns whether verification succeeded along with the user's subject claim.
If verification succeeds, NEAR Auth validates the returned subject and builds the derivation path `{guard_id}#{user_subject}`.
The `sign_payload` is SHA-256 hashed. For `ecdsa` and `eddsa`, the hash is additionally hex-encoded before being placed in the request.
NEAR Auth calls the MPC contract at `mpc_address` with the algorithm-appropriate request (`SignRequest` for `secp256k1`, `SignRequestV2` for `ecdsa` / `eddsa`), forwarding the attached deposit.
The MPC network collaboratively produces the signature from its distributed key shares.
The signature is returned to the caller, and the deposit is refunded. From here, a [relayer](/protocol/concepts/relayer) can submit the resulting (delegate) transaction — optionally sponsoring the gas.
***
## Signature responses
The MPC returns one of two response shapes, wrapped in an untagged `SignResponseAny` enum. The variant depends on the signature scheme.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub struct AffinePoint {
affine_point: String,
}
pub struct Scalar {
scalar: String,
}
pub struct EcdsaSignResponse {
pub scheme: String,
pub big_r: AffinePoint,
pub s: Scalar,
pub recovery_id: u8,
}
```
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub struct EdDsaSignResponse {
pub scheme: String,
pub signature: Vec,
}
```
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub enum SignResponseAny {
Ecdsa(EcdsaSignResponse),
EdDsa(EdDsaSignResponse),
}
```
***
## Deposit and refund behavior
`FastAuth.sign` is `#[payable]`: the caller must attach a deposit that covers the gas and network fees for the MPC computation. NEAR Auth forwards that deposit to the MPC contract when it issues the sign request.
The deposit is always returned to the original caller, whether or not signing succeeds:
* **Verification fails** — if the guard rejects the JWT (or the cross-contract call errors), the flow stops before reaching the MPC and the full deposit is transferred back to the caller.
* **MPC signing fails** — if the MPC call errors, the deposit is refunded to the caller and no signature is returned.
* **Signing succeeds** — the deposit is refunded to the caller and the signature is returned.
Because the deposit is refunded in every branch, the net cost to the caller is only the gas actually consumed — but the caller must still attach enough up front to cover the MPC computation, or the request will fail.
***
## Next steps
How `verify` and `sign` chain guard verification into MPC signing.
Submit signed (delegate) transactions and sponsor gas for your users.
What the guard checks before a signature is ever produced.
The full login-to-signature flow, end to end.
# Relayer & meta-transactions
Source: https://docs.auth.near.org/protocol/concepts/relayer
How a relayer sponsors gas by submitting MPC-signed delegate actions as NEP-366 meta-transactions.
A relayer is a service that turns an MPC signature into an on-chain transaction your users don't have to pay for. It takes a signed delegate action, wraps it as a NEP-366 meta-transaction, and submits it to NEAR from its own account — covering the gas so your users can transact without ever holding NEAR.
Pairing NEAR Auth with a relayer is what makes fully gasless flows possible: users log in with a Web2 identity, the [MPC network](/protocol/concepts/mpc) produces a signature, and the relayer pays for and broadcasts the result.
A relayer is optional. You can always broadcast a fully signed transaction yourself and pay gas from the user's own account. A relayer exists specifically to sponsor gas on the user's behalf.
***
## Meta-transactions in one minute
NEAR's [NEP-366 meta-transaction](https://nomicon.io/Standards/meta-transactions) standard separates the party that *authorizes* an action from the party that *pays* for it:
* A **delegate action** describes what the user wants to do — a receiver account and a list of actions — and is signed with the user's key. It is not a transaction on its own.
* A **relayer** wraps that signed delegate action inside a `SignedDelegate` action and submits it as its own transaction. The relayer's account pays the gas; the inner action still executes as if the user sent it.
In NEAR Auth, the user's "key" is the [MPC-derived key](/protocol/concepts/mpc) for their identity. The user never signs with a local private key — the delegate action is authorized by an MPC signature produced only after the [Auth0 JWT is verified on-chain](/protocol/concepts/jwt) by the [NEAR Auth contract](/protocol/contracts/fast-auth). The relayer then supplies the gas.
Three pieces come together for a gasless call: the **delegate action** (what to do), the **MPC signature** (authorization, gated by JWT verification), and the **NEP-366 wrapper** the relayer submits (who pays).
***
## How the SDK uses it
You don't drive the relayer by hand. The React SDK's signer exposes `signAndSendDelegateAction(...)`, which runs the whole gasless flow for you: it asks the [provider](/sdks/javascript-provider) to authorize the delegate action, collects the resulting signature request (the guard id, JWT, and payload), and submits it through a relayer, returning the `FinalExecutionOutcome`.
Contrast this with `signAndSendTransaction`, which is *not* gasless: it fetches the MPC signature, then builds and broadcasts the final transaction from the user's own account, paying gas normally. Use `signAndSendDelegateAction` whenever you want a relayer to cover gas.
In the Browser SDK the signer has no `signAndSendDelegateAction`. There you drive the flow manually — `requestDelegateActionSignature` → `getSignatureRequest` → `createSignAction` — and submit through a relayer yourself.
***
## Running or integrating a relayer
Running a relayer means operating a funded NEAR account that pays for every meta-transaction it submits, so it is a spend surface: put it behind your own authentication and rate limits, keep its signing accounts funded, and restrict the guard and issuer it accepts to exactly the ones your app uses.
NEAR maintains the reference relayer implementation and the meta-transaction standard. Start here:
The NEP-366 meta-transaction standard and how delegate actions are relayed.
Reference relayer, RPC, and the rest of the NEAR protocol docs.
***
## Next steps
Request a signature and send a NEAR transaction — gasless or self-paid — from an SDK.
How the MPC network derives per-identity keys and produces signatures.
The full Auth0 → JWT → contract → MPC → relayer flow, end to end.
# Auth0 Guard
Source: https://docs.auth.near.org/protocol/contracts/auth0-guard
The NEAR Auth guard contract that verifies Auth0 JWTs on-chain — RS256 signature, issuer, expiry, audience, and the fatxn transaction binding.
The **Auth0 Guard** is the on-chain contract that proves an Auth0 login is authentic before NEAR Auth ever asks the MPC network to sign. It verifies the RS256 signature on an Auth0-issued [JWT](/protocol/concepts/jwt), checks the standard claims, and — most importantly — confirms the JWT was minted for *this exact deployment* and *this exact transaction*. It is deployed on mainnet at `auth0.jwt.fast-auth.near` and on testnet at `auth0.jwt.fast-auth.testnet`.
It is the reference implementation of the `JwtGuard` trait and the default guard for the [Auth0 provider](/protocol/concepts/auth0). The [JWT Guard Router](/protocol/contracts/jwt-guard-router) routes verification requests to it under the guard name `jwt#auth0`.
The guard only **verifies**. It never holds keys or produces signatures. When verification succeeds it returns the JWT's `sub` claim, which the [NEAR Auth contract](/protocol/contracts/fast-auth) uses to derive the per-user MPC signing path.
***
## What it verifies
Every call to `verify` runs the full `JwtGuard` pipeline, then layers Auth0-specific custom-claim checks on top. All of the following must pass, or verification fails:
The JWT signature is verified with RSA PKCS#1 v1.5 (SHA-256) against the guard's stored 2048-bit public keys.
The token's `iss` claim must match the `issuer` argument passed by the caller.
`exp` must be in the future and `nbf` (if present) must already be in effect at the current block time.
`aud` must contain the guard's own account id — the account the contract is deployed to.
The custom `fatxn` claim must be byte-for-byte equal to the `sign_payload` passed in.
The JWT is bounded (max 7 KB) before any parsing or cryptography runs.
### The two custom claims
The base `JwtGuard` trait handles the signature and the standard `iss` / `exp` / `nbf` claims. The Auth0 Guard adds its own `verify_custom_claims` step, which deserializes the JWT payload into this structure:
```rust custom_claims.rs theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub struct CustomClaims {
pub fatxn: Vec, // the encoded transaction payload
pub aud: serde_json::Value, // string or array, per the OIDC spec
}
```
It then enforces two independent binding checks.
**Audience must contain the guard's own account id.** Per the OIDC spec, `aud` may be a single string or an array of strings, so the guard accepts either form and looks for its own `env::current_account_id()` among them:
```rust verify_custom_claims.rs theme={"theme":{"light":"github-light","dark":"github-dark"}}
let expected = env::current_account_id().to_string();
if !audience_matches(&claims.aud, &expected) {
return (false, "audience mismatch".to_string());
}
```
This prevents a JWT minted for one deployment from being replayed against another — a token targeting the testnet guard cannot be used against mainnet, and vice versa.
**`fatxn` must equal the `sign_payload`.** The `fatxn` claim is the encoded transaction or delegate-action payload the user authorized at login time. The guard requires it to match the `sign_payload` the caller is asking to sign, exactly:
```rust verify_custom_claims.rs theme={"theme":{"light":"github-light","dark":"github-dark"}}
if claims.fatxn != sign_payload {
return (false, "Transaction payload mismatch".to_string());
}
```
The `fatxn` binding is what makes NEAR Auth safe against a compromised relayer or frontend. A valid JWT can only ever authorize the one transaction it was issued for — a signature for any other payload is impossible, because the guard rejects the request before the MPC network is ever consulted.
If both binding checks pass, `verify_custom_claims` returns success and the guard returns the token's `sub` claim to the caller.
***
## Methods
### `verify`
The main entry point, called by the [NEAR Auth contract](/protocol/contracts/fast-auth) or the [JWT Guard Router](/protocol/contracts/jwt-guard-router) during a signing flow. It is a read-only method (no state change) and runs the full verification pipeline described above.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub fn verify(
&self,
issuer: String,
jwt: String,
sign_payload: Vec,
predecessor: AccountId,
) -> (bool, String)
```
| Parameter | Type | Description |
| -------------- | ----------- | --------------------------------------------------------------------------------------------------------- |
| `issuer` | `String` | The expected JWT issuer, e.g. `https://login.testnet.fast-auth.com/`. Must equal the token's `iss` claim. |
| `jwt` | `String` | The full Auth0-issued JWT to verify. |
| `sign_payload` | `Vec` | The encoded transaction payload; must equal the token's `fatxn` claim. |
| `predecessor` | `AccountId` | The original caller's account id, forwarded through the routing chain. |
**Returns** a `(bool, String)` tuple: the boolean is `true` when the JWT is valid, and the string carries the `sub` claim on success or an error message (`"audience mismatch"`, `"Transaction payload mismatch"`, and so on) on failure.
### `set_public_keys`
Replaces the guard's stored RSA public keys. Auth0's signing keys rotate, so the owner keeps the guard's key set current; the same method is used for emergency rotation after a suspected key compromise.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub fn set_public_keys(&mut self, public_keys: Vec)
```
Each key is a modulus/exponent pair, and every key is validated before it is stored:
```rust JwtPublicKey.rs theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub struct JwtPublicKey {
pub n: Vec, // RSA modulus
pub e: Vec, // RSA exponent
}
```
`set_public_keys` is **owner-only**. Any call from an account other than the stored owner panics with `"Only the owner can call this function"`. The guard's keys are owner-managed — this is the key distinction from the DAO- and attestation-managed guards described under [Advanced](/protocol/advanced/custom-issuer-guard).
The guard supports multiple public keys at once, so a signature verifies if it matches *any* stored key. That lets an operator publish the next key before the old one is retired, avoiding a verification gap during rotation.
The guard also exposes standard owner-management and upgrade methods, all owner-gated:
* `owner()` — returns the current owner `AccountId`.
* `change_owner(new_owner)` — transfers ownership; only the current owner may call it.
* `update_contract()` — deploys new contract code to the guard account and runs a `migrate` state migration.
On initialization, `init(owner, public_keys)` sets the owner and validates every supplied public key before storing it.
***
## How it fits the signing flow
The guard is invoked in the middle of a NEAR Auth signature request — it is never called directly by the SDK.
The user authenticates through the [Auth0 provider](/protocol/concepts/auth0), which embeds the encoded transaction in the `fatxn` claim and sets `aud` to the target guard's account id.
The frontend calls `sign(guard_id, jwt, sign_payload, algorithm)` on the [NEAR Auth contract](/protocol/contracts/fast-auth) with `guard_id: "jwt#auth0"`.
The [JWT Guard Router](/protocol/contracts/jwt-guard-router) resolves `jwt#auth0` to `auth0.jwt.fast-auth.near` (or `.testnet`) and calls `verify`.
RS256 signature, `iss`, `exp`/`nbf`, `aud` contains this account, and `fatxn == sign_payload`. On success it returns the `sub` claim.
NEAR Auth uses the returned `sub` to derive the deterministic MPC path and requests the signature. The verified transaction is signed and can be submitted, optionally gasless via a relayer.
***
## Related
How the token is structured, the `fatxn` claim, and on-chain RS256 verification.
How Auth0 mints the JWT and sets the signing audience for this guard.
The registry that maps `jwt#auth0` to this guard's account.
The entry point that calls into the guard during a signing flow.
# NEAR Auth contract
Source: https://docs.auth.near.org/protocol/contracts/fast-auth
The entry-point contract that routes verification to guards and orchestrates MPC signing on NEAR.
The **NEAR Auth contract** (code name `FastAuth`, deployed at `fast-auth.near` on mainnet and `fast-auth.testnet` on testnet) is the on-chain entry point for the whole protocol. Every signature request from an SDK lands here. The contract verifies the request through the right guard, then asks the [MPC network](/protocol/concepts/mpc) to produce a signature — it never holds a private key itself.
Think of it as the orchestrator: it owns a registry of guards, routes each request by `guard_id`, forwards verified requests to MPC, and refunds your deposit if anything fails along the way.
For deployed addresses on each network, see [Mainnet resources](/resources/mainnet). For the guard registry it routes into, see [JWT Guard Router](/protocol/contracts/jwt-guard-router).
***
## What it does
Extracts the prefix from `guard_id` and dispatches to the matching guard contract — `jwt` routes to the JWT Guard Router.
Delegates JWT verification to the guard. No signature is ever produced unless the guard approves the request.
On success, forwards a signing request to the MPC contract at the deterministic path `{guard_id}#{sub}`.
Returns your attached deposit to the caller if verification is rejected or MPC signing fails.
***
## Public methods
The contract exposes a small surface: two call methods for end users (`verify` and `sign`), plus owner-only administration for the guard registry, MPC configuration, and the pause switch.
| Method | Access | Description |
| ------------------------------------------------------------------------------------------------ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `sign(guard_id, verify_payload, sign_payload, algorithm)` | Public, `#[payable]` | Verify the payload through the guard, then sign `sign_payload` via MPC. Returns a `Promise` resolving to the signature. |
| `verify(guard_id, verify_payload, sign_payload)` | Public (view-like call) | Verify the payload through the guard only. Returns a `Promise` resolving to `(bool, String)` — success flag and the user identifier. |
| `add_guard(guard_id, guard_address)` | Owner only | Register a guard contract under `guard_id`. The id must not contain `#`. |
| `remove_guard(guard_id)` | Owner only | Remove a guard from the registry. |
| `get_guard(guard_id)` | Public view | Return the account id registered for `guard_id`. Panics if it does not exist. |
| `set_mpc_address(mpc_address)` | Owner only | Set the MPC contract account the signing requests are sent to. |
| `set_mpc_key_version(mpc_key_version)` | Owner only | Set the MPC key version (`u32`, default `0`) used by the legacy `secp256k1` request. |
| `set_mpc_domain_id(mpc_domain_id)` | Owner only | Set the MPC domain id (`u64`, default `1`) used by `ecdsa` / `eddsa` requests. |
| `pause()` | Pauser only | Halt the contract. Most methods panic while paused. |
| `unpause()` | Owner only | Resume the contract after a pause. |
| `change_owner(new_owner)` | Owner only | Transfer administrative ownership. |
| `set_pauser(pauser)` | Owner only | Set the account allowed to call `pause()`. |
| `paused()` / `owner()` / `mpc_address()` / `mpc_key_version()` / `mpc_domain_id()` / `version()` | Public view | Read the corresponding piece of contract state. |
`pause()` can be called by the dedicated **pauser** account for a fast emergency stop, but only the **owner** can `unpause()`. Adding/removing guards and changing MPC config are all owner-only.
***
## `guard_id` routing
Every request is addressed to a guard through its `guard_id`. The contract supports a hierarchical id format that uses `#` as a separator, and routes on the **prefix** before the first `#`:
| `guard_id` | Prefix used for routing | Meaning |
| ----------- | ----------------------- | --------------------------------------------------------------------------------------------------- |
| `jwt` | `jwt` | Routes to the guard registered as `jwt` (the JWT Guard Router). |
| `jwt#auth0` | `jwt` | Routes to the same `jwt` guard, passing the full id so the router can sub-route to the Auth0 guard. |
The prefix must be non-empty, so an id like `#auth0` or an empty string is rejected. Because the Auth0 happy path registers the router under `jwt`, a request with `guard_id` starting with `jwt` always reaches the [JWT Guard Router](/protocol/contracts/jwt-guard-router), which forwards to the correct downstream guard.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Simplified routing inside the contract
let guard_prefix = self.get_guard_prefix(guard_id.clone()); // "jwt#auth0" -> "jwt"
let guard_address = self.guards.get(&guard_prefix)
.cloned()
.unwrap_or_else(|| env::panic_str("Guard does not exist"));
external_guard::ext(guard_address)
.verify(guard_id, verify_payload, sign_payload, env::predecessor_account_id());
```
***
## Supported algorithms
The `algorithm` argument to `sign` is parsed case-insensitively into one of three values. Each maps to a different MPC request shape:
| Algorithm | Curve / scheme | MPC request |
| ----------- | --------------------------- | ------------------------------------- |
| `secp256k1` | ECDSA on secp256k1 (legacy) | `SignRequest`, uses `mpc_key_version` |
| `ecdsa` | ECDSA with domain support | `SignRequestV2`, uses `mpc_domain_id` |
| `eddsa` | EdDSA (Ed25519) | `SignRequestV2`, uses `mpc_domain_id` |
Any other value panics with an "Unsupported algorithm" error. In all three cases the contract SHA-256 hashes `sign_payload` before handing it to MPC, and derives the signing path deterministically as `{guard_id}#{sub}`, where `sub` is the user identifier returned by the guard.
***
## Deposit and refund
`sign` is `#[payable]` because MPC signing has an on-chain cost. You attach a deposit when calling it, and the contract forwards that deposit to the MPC contract to cover the signature. The contract is careful to return your NEAR whenever the flow does not complete:
If the guard rejects the JWT (bad signature, wrong issuer/audience, expired, or mismatched `fatxn`), the contract transfers the full attached deposit back to the caller and stops.
If verification passed but the MPC contract returns an error, the callback refunds the original deposit to the caller and returns `None`.
On a successful signature, the original deposit is still returned to the caller and the MPC signature is returned from the call.
Always attach enough deposit to cover the MPC cost. If you underpay, the MPC request fails and the flow refunds and aborts without producing a signature.
***
## Where it sits in the flow
The NEAR Auth contract is step 3–5 of the end-to-end Auth0 flow: your app calls `sign(guard_id, jwt, sign_payload, algorithm)`, the contract routes to the guard for JWT verification, and on success it requests the MPC signature at path `{guard_id}#{sub}`. The returned signature can then be submitted to NEAR — optionally gasless via a relayer.
The registry the `jwt` prefix routes into, and how it dispatches to the Auth0 guard.
How distributed key shares produce a signature at a deterministic derivation path.
How the entry point, router, and guards fit together.
Mainnet account ids for the contract, router, guards, and MPC.
# JWT Guard Router
Source: https://docs.auth.near.org/protocol/contracts/jwt-guard-router
The on-chain registry that maps guard names to guard contracts and routes NEAR Auth verification to the right one.
The **JWT Guard Router** is the routing layer of NEAR Auth. It keeps a registry that maps a guard name to the account of a guard contract, and it forwards each verification request from the NEAR Auth contract to the correct guard. This is what lets NEAR Auth support many identity providers — Auth0 today, others later — without changing the core contract.
On mainnet the router is deployed at `jwt.fast-auth.near`; on testnet at `jwt.fast-auth.testnet`. It is registered inside the [NEAR Auth contract](/protocol/contracts/fast-auth) as the guard named `jwt`, which is why every guard id that reaches it looks like `jwt#GUARD_NAME`.
The router itself never verifies JWTs. It only decides **which** guard should, then delegates. The actual RS256 verification and claim checks happen in the target guard, such as the [Auth0 Guard](/protocol/contracts/auth0-guard).
***
## Where the router sits
NEAR Auth splits identity verification across three contracts so each layer stays small and replaceable:
Your app calls `sign(guard_id, verify_payload, sign_payload, algorithm)`. The `FastAuth` contract looks at the guard id prefix and routes JWT-based ids (`jwt#...`) to the router registered under the `jwt` name.
The router splits the guard id into `jwt` and `GUARD_NAME`, looks up `GUARD_NAME` in its registry, and forwards `verify(...)` to that guard contract.
The guard performs the real work — RS256 signature verification, issuer/audience/expiry checks, and matching the `fatxn` claim — then returns whether the token is valid along with the user subject.
***
## Contract state
The contract stores two fields:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
#[near(contract_state)]
pub struct JwtGuardRouter {
/// Mapping of guard names to their account IDs
guards: LookupMap,
/// Account ID of the contract owner
owner: AccountId,
}
```
| Field | Type | Description |
| -------- | ------------------------------ | ------------------------------------------------------------------------- |
| `guards` | `LookupMap` | Registry mapping each guard name to the account id of its guard contract. |
| `owner` | `AccountId` | The account allowed to add or remove guards and transfer ownership. |
The registry is a `LookupMap`, so lookups are O(1) and the contract only pays storage for the entries it actually holds. It is initialized with `init(owner)`, which sets the owner and starts with an empty registry.
***
## Guard id format
Every id that reaches the router must follow the shape `jwt#GUARD_NAME`:
* `jwt` — the prefix that routed the request here from the NEAR Auth contract.
* `GUARD_NAME` — the name of a guard registered in this router.
For example, if a guard named `auth0` is registered, the full guard id you pass to the NEAR Auth contract is `jwt#auth0`. The router validates this format before doing anything else and panics on an id that is not exactly `jwt#GUARD_NAME`. Because of this, guard names themselves may never contain the `#` character.
***
## Methods
### `add_guard`
Registers a new guard name and points it at a guard contract account. Owner-only and `#[payable]` — the caller must attach a deposit that covers storage plus a contingency amount.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
#[payable]
pub fn add_guard(&mut self, guard_name: String, guard_account: AccountId)
```
| Param | Type | Description |
| --------------- | ----------- | ---------------------------------------------------------------- |
| `guard_name` | `String` | Unique name for the guard. Must not contain `#`; max 2048 bytes. |
| `guard_account` | `AccountId` | Account id of the guard contract. Max 64 bytes. |
The call is rejected unless every rule holds:
* The caller is the owner.
* `guard_name` does not contain `#`.
* `guard_name` is at most `GUARD_NAME_MAX_BYTES_LENGTH` (2048 bytes).
* `guard_account` is at most `MAX_ACCOUNT_BYTES_LENGTH` (64 bytes).
* `guard_name` is not already registered.
* The attached deposit covers the required amount.
The required deposit is computed from the maximum possible entry size so an entry can always be stored, plus a fixed contingency:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
env::storage_byte_cost()
* (GUARD_NAME_MAX_BYTES_LENGTH + MAX_ACCOUNT_BYTES_LENGTH)
+ CONTINGENCY_DEPOSIT
```
| Constant | Value |
| ----------------------------- | ---------- |
| `GUARD_NAME_MAX_BYTES_LENGTH` | 2048 bytes |
| `MAX_ACCOUNT_BYTES_LENGTH` | 64 bytes |
| `CONTINGENCY_DEPOSIT` | 1 NEAR |
### `get_guard`
Resolves a guard name to its contract account. This is a view method; it panics if the guard name is not registered.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub fn get_guard(&self, guard_name: String) -> AccountId
```
| Param | Type | Description |
| ------------ | -------- | --------------------------------------------------------------------------- |
| `guard_name` | `String` | The registered guard name to look up (the `GUARD_NAME` part of a guard id). |
Note that `get_guard` takes the bare guard name, not the full `jwt#GUARD_NAME` id — the `verify` flow strips the `jwt` prefix before calling it internally.
### `remove_guard`
Removes a guard from the registry, returning the storage deposit to the guard account. Owner-only; panics if the guard does not exist.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub fn remove_guard(&mut self, guard_name: String)
```
| Param | Type | Description |
| ------------ | -------- | ------------------------------------ |
| `guard_name` | `String` | The registered guard name to remove. |
Removing a guard immediately stops routing for that identity provider. Any guard id that resolves to the removed name will panic on the next `verify` call, so remove a guard only when you are certain no live integrations depend on it.
***
## How verification is routed
When the NEAR Auth contract delegates a JWT verification, it calls the router's `verify` method:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
pub fn verify(
&self,
guard_id: String, // "jwt#GUARD_NAME"
verify_payload: String, // the JWT to verify
sign_payload: Vec, // the payload the MPC network will sign
predecessor: AccountId, // the original caller, passed through from FastAuth
) -> Promise
```
Internally the router does three things and then hands off:
1. **Validate and split the id.** It asserts `guard_id` is exactly `jwt#GUARD_NAME` and extracts `GUARD_NAME`.
2. **Resolve the guard.** It calls `get_guard(GUARD_NAME)` to find the guard contract account (panicking if the name is unknown).
3. **Delegate.** It makes a cross-contract call to that guard's `verify`, forwarding the guard name, the JWT, the sign payload, and the original `predecessor`, then attaches a callback.
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
jwt_guard::ext(guard_account)
.verify(guard_name.clone(), verify_payload, sign_payload, predecessor)
.then(Self::ext(env::current_account_id()).on_verify_callback(guard_name))
```
The `on_verify_callback` processes the guard's response and returns a tuple back up the chain:
```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
(bool, String, String) // (valid, user_subject, guard_name)
```
* **`valid`** — whether the guard accepted the JWT.
* **`user_subject`** — the `sub` claim identifying the user (empty when invalid).
* **`guard_name`** — the guard that handled verification (empty when invalid).
On success, NEAR Auth uses `guard_name` together with the user subject to derive the MPC signing path (`{guard_id}#{sub}`), so the same login always controls the same NEAR account. If the guard reports failure, or the cross-contract call errors, verification does not proceed to signing.
***
## Ownership and upgrades
Administrative methods are gated by `only_owner`, which panics unless the caller matches the stored `owner`.
| Method | Description |
| ------------------------- | ------------------------------------------------------------------------------------- |
| `owner()` | Returns the current owner account id. |
| `change_owner(new_owner)` | Transfers ownership. Owner-only. |
| `update_contract()` | Deploys new contract code and calls `migrate` to run any state migration. Owner-only. |
Because guard registration is owner-controlled, the set of supported identity providers is governed rather than open — a new provider only becomes usable once its guard is deployed and registered here.
***
## Next steps
The entry point that routes `jwt#...` guard ids to this router.
The default guard the router delegates to for Auth0 logins.
# Contracts overview
Source: https://docs.auth.near.org/protocol/contracts/overview
The modular on-chain system behind NEAR Auth — entry point, router, guards, and attestation working together to verify JWTs and drive MPC signing.
The on-chain half of NEAR Auth is a set of smart contracts that connect an authenticated user to the MPC network so transactions and payloads can be signed securely. The system is built to be **modular**: different identity providers (Auth0 and custom OIDC issuers) plug in as interchangeable **guard** contracts, without touching the entry point.
This design gives you three properties out of the box:
* **Flexible authentication** — support multiple identity providers through swappable guard contracts.
* **Secure signing** — every JWT is cryptographically verified on-chain before any signature is produced.
* **Decentralized key management** — verification keys are governed by the attestation contract and an attester quorum, not a single party.
Auth0 is the default provider for NEAR Auth. Custom issuers and attestation-managed keys are advanced topics covered under [Protocol → Advanced](/protocol/advanced/custom-issuer-guard).
***
## The contract categories
The system is organized into four responsibilities. Each maps to one or more contracts.
The `FastAuth` contract is the single gateway users call. It resolves which guard should verify a request, and — on success — forwards the signing request to the MPC network.
The `JwtGuardRouter` is a registry that maps a guard name to its guard contract account, delegating verification to the right provider.
Middleware contracts that verify JWTs from a specific identity provider. Each implements the shared `JwtGuard` trait: RS256 signature checks, issuer/expiry validation, and provider-specific custom claims.
The `Attestation` contract manages verification public keys through a quorum of trusted attesters, so keys can only change when multiple parties agree.
***
## How the contracts interact
When a user wants to sign, the request flows through the entry point, into the router, out to a guard for verification, and — only on success — to the MPC network. The signature then travels back the same way.
1. **User request** — the user calls `sign` on the `FastAuth` contract with their JWT and the payload to sign.
2. **Guard resolution** — `FastAuth` resolves the guard from the `guard_id`. When the prefix is `jwt`, the request is routed to the `JwtGuardRouter`.
3. **JWT verification** — the appropriate guard verifies the JWT signature (RS256) and its claims.
4. **MPC signing** — on successful verification, `FastAuth` forwards the signing request to the MPC network.
5. **Signature return** — the MPC signature is returned back through `FastAuth` to the user.
```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
┌─────────┐
│ User │
└────┬────┘
│ 1. sign(JWT + payload)
▼
┌────────────────────────────────┐
│ NEAR Auth │
│ (Entry Point) │
└────┬───────────────────────────┘
│ 2. guard_id prefix = 'jwt'
▼
┌────────────────────────────────┐
│ JwtGuardRouter │
│ (Router) │
└────┬──────────────────┬────────┘
│ 3a │ 3b
▼ ▼
┌──────┐ ┌──────────────┐
│Auth0 │ │CustomIssuer │
│Guard │ │Guard │
└───┬──┘ └──────┬───────┘
│ │ verify
│ │ public keys
│ ▼
│ ┌──────────────────────────┐
│ │ Attestation │
│ │ (Key Management) │
│ └──────────────────────────┘
│
│ 4. verification success
▼
┌────────────────────────────────┐
│ NEAR Auth │
└────┬───────────────────────────┘
│ 5. forward signing request
▼
┌────────────────────────────────┐
│ MPC Network │
│ (Signing Service) │
└────┬───────────────────────────┘
│ 6. return signature → NEAR Auth → 7. User
▼
┌─────────┐
│ User │
└─────────┘
```
For the end-to-end request lifecycle — including how Auth0 embeds the encoded transaction in the JWT and how the relayer submits the final transaction — see [How it works](/protocol/how-it-works).
***
## Guards compared
All guards implement the same `JwtGuard` trait, so `FastAuth` treats them uniformly. Where they differ is the provider they trust, how their verification keys are managed, and which custom claims they check.
| Guard | Provider | Key management | Custom claims |
| ------------------- | ----------- | ----------------------------- | ------------------------------------------ |
| `Auth0Guard` | Auth0 | Owner-managed | `fatxn` claim matching |
| `CustomIssuerGuard` | Custom OIDC | DAO-managed (via attestation) | `fatxn` claim matching (no audience check) |
* **`Auth0Guard`** is the default. It checks the `iss` and `aud` claims (the audience must contain the guard account) and matches the `fatxn` claim against the signing payload. Its RSA verification keys are owner-managed.
* **`CustomIssuerGuard`** verifies JWTs from any custom OIDC provider. It checks `iss` and `fatxn` but performs **no audience check**, and its keys are DAO-managed through attestation.
Every guard verifies JWTs signed with **RS256** using RSA PKCS#1 v1.5 and 2048-bit keys. The JWT carries the standard `sub`, `iss`, `exp`, `nbf`, and `aud` claims, plus the NEAR Auth–specific `fatxn` claim, which holds the encoded transaction or delegate-action payload.
***
## Security model
The architecture layers several independent defenses, so no single check is load-bearing on its own.
Guards verify the cryptographic signature of every JWT using RS256 before trusting any of its contents.
Each guard validates specific claims — issuer, expiration, and provider-specific custom claims like `fatxn` — so a valid signature alone is never enough.
The attestation contract only lets verification keys change when multiple trusted attesters agree, preventing unilateral key swaps.
Administrative functions are gated by role-based permissions (DAO, CodeStager, CodeDeployer, and others).
Critical contracts support pausing to contain and mitigate security incidents.
***
## Explore the contracts
Start with the entry point and router, then dig into the default Auth0 guard. Custom issuers and attestation are covered under Advanced.
The entry-point contract — `sign`, `verify`, guard management, MPC config, and pause controls.
The registry that maps guard names to guard contract accounts.
The default guard — Auth0 JWT verification, audience checks, and `fatxn` matching.
Bring your own OIDC provider with DAO-managed keys.
Quorum-based public-key management for guards.
# How it works
Source: https://docs.auth.near.org/protocol/how-it-works
Follow a NEAR Auth signature end to end — from an Auth0 login to an MPC-produced signature verified on-chain.
NEAR Auth turns a Web2 login into a NEAR signature without ever exposing a private key. This page walks the full Auth0 signing flow, from the moment a user logs in to the moment a relayer submits the signed transaction on-chain. Along the way you'll see how the encoded transaction travels inside the JWT, how the on-chain contracts route and verify it, and how the MPC network derives a per-user key.
For the individual building blocks, see [JWTs](/protocol/concepts/jwt), [Auth0](/protocol/concepts/auth0), and [MPC signing](/protocol/concepts/mpc). For the contracts themselves, start at the [contracts overview](/protocol/contracts/overview).
***
## The flow at a glance
The user authenticates through the provider (`JavascriptProvider` on web, `ReactNativeProvider` on mobile) via a popup or redirect. Auth0 issues an RS256-signed JWT identifying the user through its `sub` claim.
To sign a NEAR transaction, the app calls `requestTransactionSignature({ transaction })` (or `requestDelegateActionSignature({ delegateAction })`). The provider re-authenticates against Auth0 with the encoded transaction bound into the JWT as the custom **`fatxn`** claim. The result is a fresh JWT whose signature covers the exact payload to be signed.
The signer calls `sign(guard_id, verify_payload, sign_payload, algorithm)` on the NEAR Auth contract (`fast-auth.near` / `fast-auth.testnet`). Here `verify_payload` is the Auth0 JWT, `sign_payload` is the transaction hash to be signed, and `algorithm` is one of `secp256k1`, `ecdsa`, or `eddsa`.
`FastAuth` inspects the `guard_id`. When the prefix is **`jwt`**, it delegates verification to the `JwtGuardRouter` (`jwt.fast-auth.near` / `jwt.fast-auth.testnet`), which looks up the concrete guard by name.
The router forwards the request to the `Auth0Guard` (`auth0.jwt.fast-auth.near` / `auth0.jwt.fast-auth.testnet`). The guard verifies the RS256 signature using owner-managed RSA public keys, then validates the claims: the issuer (`iss`), the audience (`aud` must contain the guard account), token validity (`exp` / `nbf`), and — critically — that the **`fatxn`** claim equals the `sign_payload`. This last check binds the JWT to exactly the transaction being signed, so a token can never be replayed against a different payload.
On successful verification, the guard returns the user's `sub`, and `FastAuth` constructs the derivation path `{guard_id}#{sub}` (for example `jwt#auth0#google-oauth2|123456789`). It SHA-256 hashes the `sign_payload` and forwards the request to the MPC network (`v1.signer` / `v1.signer-prod.testnet`), which collaboratively produces a signature from distributed key shares — no single party ever holds the full key. Derivation is deterministic, so the same identity always controls the same NEAR account.
The signature is returned to the caller. Your app can broadcast the signed transaction directly, or hand it to a [relayer](/protocol/concepts/relayer) to submit it — optionally gasless via a delegate action, so users transact without holding NEAR.
If verification or MPC computation fails, the deposit attached to cover gas and network fees is refunded to the original caller.
***
## Contract interaction diagram
The diagram below traces a request through the on-chain contracts. The `FastAuth` entry point routes to the `JwtGuardRouter` when the `guard_id` prefix is `jwt`, the router delegates to the matching guard, and — for Auth0 — verification succeeds without touching the `Attestation` contract, since Auth0 keys are owner-managed rather than attestation-based.
```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
┌─────────┐
│ User │
└────┬────┘
│ 1. sign(JWT + payload)
│
▼
┌─────────────────────────────────┐
│ NEAR Auth │
│ (Entry Point) │
└────┬────────────────────────────┘
│ 2. guard_id prefix = 'jwt'
│
▼
┌─────────────────────────────────┐
│ JwtGuardRouter │
│ (Router) │
└───┬──────────────────┬──────────┘
│ │
│ 3a │ 3b
│ │
▼ ▼
┌──────┐ ┌──────────────────┐
│Auth0 │ │ CustomIssuer │
│Guard │ │ Guard │
└───┬──┘ └────────┬─────────┘
│ │
│ │ Verify
│ │ public keys
│ │
│ ▼
│ ┌──────────────────────────┐
│ │ Attestation │
│ │ (Key Management) │
│ └──────────────────────────┘
│
│ 4. Verification success
│
▼
┌─────────────────────────────────┐
│ NEAR Auth │
│ (Entry Point) │
└────┬────────────────────────────┘
│ 5. Forward signing request
│
▼
┌─────────────────────────────────┐
│ MPC Network │
│ (Signing Service) │
└────┬────────────────────────────┘
│ 6. Return signature
│
▼
┌─────────────────────────────────┐
│ NEAR Auth │
│ (Entry Point) │
└────┬────────────────────────────┘
│ 7. Return signature
│
▼
┌─────────┐
│ User │
└─────────┘
```
The Auth0 path (3a) verifies keys directly on the guard. The Custom Issuer path (3b) resolves its keys through the `Attestation` contract instead — covered under [Protocol → Advanced](/protocol/advanced/custom-issuer-guard).
***
## Why `guard_id` routing matters
The `guard_id` is more than a lookup key — it's the first segment of the MPC derivation path, and its prefix decides how verification happens.
* **Prefix `jwt`** tells `FastAuth` to delegate to the `JwtGuardRouter`, which maintains a registry mapping each guard name to a guard contract account (`add_guard`, `get_guard`, `remove_guard`). For Auth0, the router resolves to the `Auth0Guard`.
* **The full `guard_id`** becomes the leading component of the derivation path `{guard_id}#{sub}`. Because the guard is baked into the path, identities are isolated between providers: a Google user under Auth0 and a user under a different guard can never derive the same NEAR key, even if their subjects collide.
This routing model is what lets NEAR Auth support multiple identity providers behind one entry point. Adding a new provider means registering a new guard in the router — the `FastAuth` entry point and the MPC signing step stay unchanged.
The derivation path is deterministic. `jwt#auth0#google-oauth2|123456789` always maps to the same MPC key, so the same login reliably controls the same NEAR account across sessions and devices.
***
## What each layer guarantees
| Layer | Responsibility | Guarantee |
| ---------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `FastAuth` | Entry point; routes by `guard_id`, coordinates MPC signing | The signature is only requested after a guard reports success |
| `JwtGuardRouter` | Resolves the `jwt`-prefixed guard by name | Requests reach the correct provider's guard |
| `Auth0Guard` | RS256 verification + `iss` / `aud` / `exp` / `fatxn` checks | The JWT is authentic, unexpired, addressed to this guard, and bound to the exact payload |
| MPC network | Distributed signing at `{guard_id}#{sub}` | A valid signature is produced without any party holding the full key |
***
## Next steps
The RS256 token, its claims, and the `fatxn` payload binding.
How the default provider issues tokens and which claims the guard checks.
Per-user key derivation, signature algorithms, and distributed signing.
The entry point, router, guards, and supporting infrastructure.
# Protocol overview
Source: https://docs.auth.near.org/protocol/overview
The three layers behind NEAR Auth — smart contracts, an MPC signing network, and optional off-chain services.
NEAR Auth lets users sign NEAR transactions with the Web2 identities they already have — Google, Apple, email, or passkeys — while their keys stay secured by a Multi-Party Computation network. This page introduces the architecture at a glance: the three layers that make it work and what each one is responsible for.
Under the hood, an on-chain contract system verifies a signed JWT, an MPC network produces the signature from distributed key shares, and optional off-chain services stitch the pieces together for your app.
***
## The three layers
NEAR Auth is composed of three cooperating layers. Only the first two are required; the third is optional and depends on your integration.
On-chain contracts that authenticate the user, verify the JWT, and coordinate with the MPC network to produce a signature.
A distributed network that holds key shares and signs without any single party ever seeing the full private key.
Optional services — such as a relayer for gasless transactions or a custom backend — that support the flow.
***
### 1. Smart contracts
The smart contracts are the core of NEAR Auth. They enable the interaction between the end user and the MPC network to sign transactions or payloads securely, and they are the only component that decides whether a signature is allowed.
The contract system is designed with modularity in mind. Different identity providers plug in as interchangeable **guard** contracts, so the same core can support Auth0 today and other providers later without changing its trust model. This design gives you:
* **Flexible authentication** — support for multiple identity providers through interchangeable guard contracts.
* **Secure signing** — JWT verification followed by MPC-based signature generation.
* **Decentralized key management** — through an attestation contract and the MPC network.
The main pieces are the `FastAuth` contract (the entry point that coordinates authentication and MPC signing), the `JwtGuardRouter` (which routes each verification request to the right guard), and the guards themselves. On the Auth0 happy path, the **Auth0 Guard** performs the actual RS256 JWT verification — checking the issuer, the audience, and that the `fatxn` claim matches the transaction being signed.
The full contract system: `FastAuth`, the JWT Guard Router, and the guards.
***
### 2. MPC network
The MPC network is a distributed system that holds key shares and produces signatures **without any single party having access to the full private key**. This is what makes NEAR Auth non-custodial: no server, and no NEAR Auth operator, can unilaterally sign on a user's behalf.
Signing is deterministic per identity. Each user's key is derived at the path `{guard_id}#{user_subject}`, so the same login always controls the same NEAR account. The network only signs after the smart contract layer has verified the JWT, which keeps authorization and key custody cleanly separated.
How distributed key shares, derivation paths, and threshold signing work.
***
### 3. Off-chain services optional
Everything above runs on-chain. In practice, most integrations also lean on a few off-chain services to smooth out the user experience:
* A **relayer** submits the signed transaction — and can sponsor gas via delegate actions, so users transact without holding NEAR.
* A **custom backend** can implement bespoke authentication flows when the default Auth0 path is not enough.
These services never hold keys and never bypass on-chain verification; they only orchestrate requests around the contracts and the MPC network.
How gasless, relayer-submitted transactions work with delegate actions.
***
## How the layers fit together
At a high level, the identity provider issues a JWT that embeds the encoded transaction, the smart contracts verify that JWT on-chain, and the MPC network signs. The building blocks that recur across all three layers are the **JWT** (the signed proof of identity and intent) and the **MPC network** (the source of every signature).
Follow a login-to-signature request end to end across all three layers.
The RS256 claims — including `fatxn` — that get verified on-chain.
New to the flow? Start with [How it works](/protocol/how-it-works) for the end-to-end walkthrough, then dive into [Contracts](/protocol/contracts/overview) and [MPC](/protocol/concepts/mpc) for the details.
***
## Going further
The Auth0 guard is the default path. NEAR Auth's modular guard design also supports alternative providers and self-hosted infrastructure — plugging in your own custom OIDC issuer, attestation-based key management, or a custom backend. Those variants live under **Protocol → Advanced**.
Custom issuers, attestation, and custom backends.
# Mainnet contracts
Source: https://docs.auth.near.org/resources/mainnet
Deployed NEAR Auth contract addresses and network configuration for NEAR mainnet.
The addresses below are the production NEAR Auth deployment on **NEAR mainnet**. Use them when you configure an SDK or inspect on-chain activity in an explorer.
Mainnet access is gated. You must be whitelisted before your app can authenticate real users against this deployment. [Apply for production access](/home/apply) — or build against the open [testnet contracts](/resources/testnet) first, which need no sign-off.
***
## Contract addresses
| Contract | Account id | Description |
| ---------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
| NEAR Auth | [`fast-auth.near`](https://nearblocks.io/address/fast-auth.near) | The entry-point contract. Verifies a JWT through a guard and requests an MPC signature. |
| JWT Guard Router | [`jwt.fast-auth.near`](https://nearblocks.io/address/jwt.fast-auth.near) | Registry that routes a `guard_id` to the guard contract responsible for verifying the JWT. |
| Auth0 Guard | [`auth0.jwt.fast-auth.near`](https://nearblocks.io/address/auth0.jwt.fast-auth.near) | Guard that RS256-verifies Auth0 JWTs and validates the `iss`, `aud`, and `fatxn` claims. |
| MPC signer | [`v1.signer`](https://nearblocks.io/address/v1.signer) | NEAR's Multi-Party Computation network. Produces signatures from distributed key shares. |
On mainnet, `auth0.jwt.fast-auth.near` is also the Auth0 **signing audience** — every JWT the guard verifies must list it in the `aud` claim. See the [Auth0 concept](/protocol/concepts/auth0) for details.
***
## Network information
| Setting | Value |
| ------------ | -------------------------------------- |
| Network | NEAR Mainnet |
| Chain id | `mainnet` |
| RPC endpoint | `https://rpc.mainnet.near.org` |
| Explorer | [nearblocks.io](https://nearblocks.io) |
When you construct a client, point `near-api-js` at the mainnet RPC and pass the mainnet account ids:
```ts main.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthClient } from "@fast-auth-near/browser-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
import { connect } from "near-api-js";
const provider = new JavascriptProvider({
network: "mainnet",
clientId: "your-auth0-client-id",
});
const { connection } = await connect({
networkId: "mainnet",
nodeUrl: "https://rpc.mainnet.near.org",
});
const client = new FastAuthClient(provider, connection, {
fastAuthContractId: "fast-auth.near",
mpcContractId: "v1.signer",
});
```
The MPC signer derives each user's key at the path `{guard_id}#{sub}`, so the same login always controls the same NEAR account across sessions.
***
## Next steps
Get whitelisted to authenticate real users in production.
The open deployment for building and testing without approval.
RPC URLs, chain ids, and explorers side by side.
# Network configuration
Source: https://docs.auth.near.org/resources/networks
Every per-network value an integrator sets — NEAR RPC, contract ids, and Auth0 — for mainnet and testnet.
NEAR Auth runs on two networks: **testnet** for building and **mainnet** for production. Every value on this page is network-specific — swap the whole set together when you move an app from testnet to mainnet. Testnet uses shared credentials you can copy today; mainnet requires an [approved application](/home/apply).
Start on testnet with the values below — no sign-off needed. When you're ready to launch, [apply for production access](/home/apply) to get your own mainnet Auth0 `clientId`.
***
## All values, side by side
Every setting your app needs, per network. The NEAR values feed `near-api-js` and the `FastAuthClient` config; the Auth0 values feed the [`JavascriptProvider`](/sdks/javascript-provider) (or `ReactNativeProvider`).
| Setting | Mainnet | Testnet |
| ----------------------- | ------------------------------ | ---------------------------------- |
| `networkId` | `mainnet` | `testnet` |
| NEAR RPC (`nodeUrl`) | `https://rpc.mainnet.near.org` | `https://rpc.testnet.near.org` |
| `fastAuthContractId` | `fast-auth.near` | `fast-auth.testnet` |
| `mpcContractId` | `v1.signer` | `v1.signer-prod.testnet` |
| Auth0 `domain` | `login.auth.near.org` | `login.testnet.fast-auth.com` |
| Auth0 `signingAudience` | `auth0.jwt.fast-auth.near` | `auth0.jwt.fast-auth.testnet` |
| Auth0 `clientId` | *your approved application* | `np8paqIpMWmNbzT4xAvOOapZBjsOpptl` |
`domain` and `signingAudience` are **optional** on the provider — the SDK ships the correct defaults for the `network` you pass, so you only set them to override a custom Auth0 setup. `clientId` is always required.
There is no shared mainnet `clientId`. The testnet `clientId` above is a public, shared demo credential — never point a production app at it. Your mainnet `clientId` comes from your own approved application. [Apply for production access →](/home/apply)
***
## What each value is for
* **`networkId`** — the NEAR network your app talks to. Selects the RPC, contracts, and MPC signer for that environment.
* **NEAR RPC (`nodeUrl`)** — the JSON-RPC endpoint `near-api-js` uses to build the connection you pass into `FastAuthClient`.
* **`fastAuthContractId`** — the account of the on-chain [NEAR Auth contract](/protocol/contracts/fast-auth) that verifies the Auth0 JWT and requests the signature.
* **`mpcContractId`** — the [MPC signer](/protocol/concepts/mpc) contract that produces the signature from distributed key shares. Full contract addresses live on the [Mainnet](/resources/mainnet) and [Testnet](/resources/testnet) reference pages.
* **Auth0 `domain`** — the Auth0 tenant that hosts the login flow.
* **Auth0 `signingAudience`** — the audience the issued JWT is scoped to; on-chain, the [Auth0 Guard](/protocol/concepts/auth0) checks this `aud` value.
* **Auth0 `clientId`** — identifies your application to Auth0.
***
## Ready-to-copy config
Drop one of these into your app and read from it. The `near` block configures the [Browser SDK](/sdks/browser-sdk) client; the `auth0` block configures the [JavaScript provider](/sdks/javascript-provider).
```json config.testnet.json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"networkId": "testnet",
"near": {
"nodeUrl": "https://rpc.testnet.near.org",
"fastAuthContractId": "fast-auth.testnet",
"mpcContractId": "v1.signer-prod.testnet"
},
"auth0": {
"network": "testnet",
"domain": "login.testnet.fast-auth.com",
"signingAudience": "auth0.jwt.fast-auth.testnet",
"clientId": "np8paqIpMWmNbzT4xAvOOapZBjsOpptl"
}
}
```
```json config.mainnet.json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"networkId": "mainnet",
"near": {
"nodeUrl": "https://rpc.mainnet.near.org",
"fastAuthContractId": "fast-auth.near",
"mpcContractId": "v1.signer"
},
"auth0": {
"network": "mainnet",
"domain": "login.auth.near.org",
"signingAudience": "auth0.jwt.fast-auth.near",
"clientId": "your-approved-application-client-id"
}
}
```
## Wiring it into the SDK
Once you've picked a config, only three things flow into the SDK: the `network` and `clientId` for the provider, and the `fastAuthContractId` / `mpcContractId` for the client. The NEAR connection is built from `networkId` and `nodeUrl`.
```ts testnet.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthClient } from "@fast-auth-near/browser-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
import { connect } from "near-api-js";
const provider = new JavascriptProvider({
network: "testnet",
clientId: "np8paqIpMWmNbzT4xAvOOapZBjsOpptl",
// domain and signingAudience are optional — SDK defaults match the network
});
const { connection } = await connect({
networkId: "testnet",
nodeUrl: "https://rpc.testnet.near.org",
});
const client = new FastAuthClient(provider, connection, {
fastAuthContractId: "fast-auth.testnet",
mpcContractId: "v1.signer-prod.testnet",
});
```
```ts mainnet.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthClient } from "@fast-auth-near/browser-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
import { connect } from "near-api-js";
const provider = new JavascriptProvider({
network: "mainnet",
clientId: "your-approved-application-client-id",
// domain and signingAudience are optional — SDK defaults match the network
});
const { connection } = await connect({
networkId: "mainnet",
nodeUrl: "https://rpc.mainnet.near.org",
});
const client = new FastAuthClient(provider, connection, {
fastAuthContractId: "fast-auth.near",
mpcContractId: "v1.signer",
});
```
Keep both configs in your repo and select one by an environment variable so switching networks is a single toggle — never a code change.
***
## Keep exploring
Deployed contract addresses, RPC, and explorer for production.
The same lookup for the testnet environment.
Get your own mainnet Auth0 credentials.
# Resources
Source: https://docs.auth.near.org/resources/overview
Deployed contract addresses and network configuration for NEAR Auth.
Everything you need to look up while building on NEAR Auth: the deployed contract account ids and the network configuration for connecting to NEAR mainnet and testnet.
Production contract addresses, RPC, and explorer for NEAR mainnet.
Development contract addresses and shared credentials for NEAR testnet.
Auth0 domains, signing audiences, and network defaults side by side.
# Testnet contracts
Source: https://docs.auth.near.org/resources/testnet
Deployed NEAR Auth contract addresses, network config, and credentials for NEAR testnet.
The addresses below are the live NEAR Auth deployment on **NEAR testnet**. Use them for development and integration testing — testnet needs no approval, and you can point your SDK at these contracts today with the shared credentials on this page.
Testnet requires no sign-off. When you're ready to go live, review the [mainnet contracts](/resources/mainnet) and [apply for production access](/home/apply).
***
## Contract addresses
| Contract | Account id | Description | Explorer |
| ---------------- | ----------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| NEAR Auth | `fast-auth.testnet` | Entry-point contract that routes verification and requests MPC signatures. | [View](https://testnet.nearblocks.io/address/fast-auth.testnet) |
| JWT Guard Router | `jwt.fast-auth.testnet` | Registry mapping each guard name to its guard contract. | [View](https://testnet.nearblocks.io/address/jwt.fast-auth.testnet) |
| Auth0 Guard | `auth0.jwt.fast-auth.testnet` | Guard that RS256-verifies Auth0 JWTs and their claims on-chain. | [View](https://testnet.nearblocks.io/address/auth0.jwt.fast-auth.testnet) |
| MPC | `v1.signer-prod.testnet` | Multi-Party Computation network that produces signatures from distributed key shares. | [View](https://testnet.nearblocks.io/address/v1.signer-prod.testnet) |
In the SDKs, `fast-auth.testnet` is the `fastAuthContractId` and `v1.signer-prod.testnet` is the `mpcContractId`. To learn what each contract does, see the [contracts overview](/protocol/contracts/overview).
***
## Network information
| Setting | Value |
| ------------ | ------------------------------------------------------ |
| Network | NEAR Testnet |
| Chain id | `testnet` |
| RPC endpoint | `https://rpc.testnet.near.org` |
| Explorer | [testnet.nearblocks.io](https://testnet.nearblocks.io) |
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { connect } from "near-api-js";
const { connection } = await connect({
networkId: "testnet",
nodeUrl: "https://rpc.testnet.near.org",
});
```
***
## Auth0 credentials
Testnet ships with a shared Auth0 client so you can start authenticating users without registering your own tenant. The JavaScript provider fills in the domain and signing audience from the `testnet` network, so `clientId` is the only value you need to supply.
| Setting | Value |
| ---------------- | ---------------------------------- |
| clientId | `np8paqIpMWmNbzT4xAvOOapZBjsOpptl` |
| domain | `login.testnet.fast-auth.com` |
| signing audience | `auth0.jwt.fast-auth.testnet` |
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
const provider = new JavascriptProvider({
network: "testnet",
clientId: "np8paqIpMWmNbzT4xAvOOapZBjsOpptl",
});
```
This `clientId` is shared across testnet apps and is intended for development only. Provision your own Auth0 credentials before moving to [mainnet](/resources/mainnet).
***
## Wire it up
The full browser client config for testnet combines the contract addresses and the Auth0 provider above.
```ts main.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthClient } from "@fast-auth-near/browser-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
import { connect } from "near-api-js";
const provider = new JavascriptProvider({
network: "testnet",
clientId: "np8paqIpMWmNbzT4xAvOOapZBjsOpptl",
});
const { connection } = await connect({
networkId: "testnet",
nodeUrl: "https://rpc.testnet.near.org",
});
const client = new FastAuthClient(provider, connection, {
fastAuthContractId: "fast-auth.testnet",
mpcContractId: "v1.signer-prod.testnet",
});
await client.login();
const signer = await client.getSigner();
```
***
## Related
Production addresses and credentials for NEAR mainnet.
Compare testnet and mainnet configuration side by side.
Log in and sign your first transaction on testnet.
# Browser SDK
Source: https://docs.auth.near.org/sdks/browser-sdk
Full reference for @fast-auth-near/browser-sdk — the framework-agnostic FastAuthClient, FastAuthSigner, and FastAuthSignature classes.
`@fast-auth-near/browser-sdk` is the framework-agnostic NEAR Auth SDK. It exposes three classes — `FastAuthClient` to log users in and hand you a signer, `FastAuthSigner` to derive keys and build NEAR actions, and `FastAuthSignature` to turn a raw MPC signature into transaction-ready bytes. Use it in vanilla JS, Vue, Svelte, Angular, or any web app that is not React.
Pair it with a platform provider — the [JavaScript provider](/sdks/javascript-provider) runs the Auth0 flow in the browser. The SDK itself only depends on the `IFastAuthProvider` interface from [`@shared/core`](/sdks/core), so the same client code works regardless of which provider you construct.
Log in, log out, and obtain an initialized signer.
Derive keys, build actions, and submit transactions.
Decode an MPC signature and recover its bytes.
***
## Installation
```bash npm theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/browser-sdk @fast-auth-near/javascript-provider near-api-js
```
```bash yarn theme={"theme":{"light":"github-light","dark":"github-dark"}}
yarn add @fast-auth-near/browser-sdk @fast-auth-near/javascript-provider near-api-js
```
```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark"}}
pnpm add @fast-auth-near/browser-sdk @fast-auth-near/javascript-provider near-api-js
```
`near-api-js` is a peer dependency — the SDK uses it for the NEAR `Connection`, transaction types, and RPC calls. You also need one provider package; on the web that is `@fast-auth-near/javascript-provider`.
New to NEAR Auth? Start with the [quickstart](/home/quickstart) for a copy-pasteable integration, then come back here for the full method surface.
***
## Quick start
Construct a provider, hand it to a `FastAuthClient`, log the user in, and get a signer. Everything after login flows through the signer.
```ts main.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthClient } from "@fast-auth-near/browser-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
import { connect } from "near-api-js";
// 1. Build a provider for your platform (web = JavascriptProvider).
const provider = new JavascriptProvider({
network: "testnet",
clientId: "your-auth0-client-id",
});
// 2. Set up a NEAR connection.
const { connection } = await connect({
networkId: "testnet",
nodeUrl: "https://rpc.testnet.near.org",
});
// 3. Create the client with the deployed contract ids.
const client = new FastAuthClient(provider, connection, {
fastAuthContractId: "fast-auth.testnet",
mpcContractId: "v1.signer-prod.testnet",
});
// 4. Authenticate, then obtain an initialized signer.
await client.login();
const signer = await client.getSigner();
// 5. Derive the user's NEAR public key.
const publicKey = await signer.getPublicKey();
```
Contract ids live in [Resources](/resources/overview). Testnet uses `fast-auth.testnet` and the MPC signer `v1.signer-prod.testnet`; mainnet uses `fast-auth.near` and `v1.signer`.
***
## FastAuthClient
The main entry point. `FastAuthClient` is a generic class that delegates authentication to the provider you pass in and produces a ready-to-use `FastAuthSigner` once the user is logged in.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
class FastAuthClient
```
### Constructor
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
constructor(
provider: P,
connection: Connection,
options: FastAuthClientOptions,
)
```
| Parameter | Type | Description |
| ------------ | ----------------------------- | ----------------------------------------------------------------------------------- |
| `provider` | `P extends IFastAuthProvider` | A provider instance, e.g. `JavascriptProvider`. Carries the Auth0 flow and session. |
| `connection` | `Connection` | A NEAR network connection from `near-api-js`. |
| `options` | `FastAuthClientOptions` | Contract ids the client and signer need. See below. |
`FastAuthClientOptions` is the same shape the signer consumes:
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
type FastAuthClientOptions = {
fastAuthContractId: string; // the NEAR Auth contract, e.g. "fast-auth.testnet"
mpcContractId: string; // the MPC signer contract, e.g. "v1.signer-prod.testnet"
};
```
### Methods
| Method | Signature | Returns | Description |
| ----------- | ------------------------------------------ | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `login` | `login(...args: Parameters
)` | Provider's login result | Starts the provider's login flow. Arguments are forwarded verbatim to `provider.login(...)`, so the accepted parameters match your provider. |
| `logout` | `logout(...args: Parameters
)` | Provider's logout result | Ends the session by delegating to `provider.logout(...)`. |
| `getSigner` | `getSigner(): Promise>` | `Promise>` | Verifies the user is logged in, constructs a `FastAuthSigner`, calls `init()` on it, and returns it ready to use. |
`getSigner()` throws a `FastAuthClientError` with code `USER_NOT_LOGGED_IN` if the user is not authenticated. Call it only after `login()` resolves, or guard it with the provider's `isLoggedIn()`.
```ts client.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
const client = new FastAuthClient(provider, connection, {
fastAuthContractId: "fast-auth.testnet",
mpcContractId: "v1.signer-prod.testnet",
});
// Arguments to login() are passed straight through to the provider.
await client.login();
try {
const signer = await client.getSigner();
// signer is already initialized — use it directly.
} catch (error) {
// Thrown with code USER_NOT_LOGGED_IN if the session is missing.
console.error("Login required:", error);
}
await client.logout();
```
Because the client is generic over `P`, `login` and `logout` inherit the exact parameter types of your provider. With the JavaScript provider, `login(options?, forceSelectAccount?)` — see the [JavaScript provider reference](/sdks/javascript-provider).
***
## FastAuthSigner
The signer is where the NEAR-facing work happens: deriving the user's public key, building `create_account` and `sign` actions, requesting signatures through the provider, and submitting signed transactions to the network.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
class FastAuthSigner
```
You normally obtain a signer from `client.getSigner()`, which constructs it and calls `init()` for you. Constructing one by hand takes the same three arguments as the client and requires an explicit `init()`.
### `init`
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
init(): Promise
```
Retrieves the user's derivation path from the provider (via `provider.getPath()`) and stores it on the signer. **Must run before any other method** — `getSigner()` calls it automatically, so you only call it yourself when you construct a `FastAuthSigner` directly.
### Account management
| Method | Signature | Returns | Description |
| --------------- | ----------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `createAccount` | `createAccount(accountId: string, options?: CreateAccountOptions): Promise` | `Promise` | Builds a `create_account` function-call `Action` that registers `accountId` with the user's derived public key. Does **not** submit it — add the action to a transaction and send it. |
| `getPublicKey` | `getPublicKey(algorithm?: Algorithm): Promise` | `Promise` | Returns the user's derived NEAR public key by calling the MPC contract's `derived_public_key` method with the signer's path and the NEAR Auth contract as predecessor. |
`createAccount` parameters:
| Parameter | Type | Default | Description |
| ------------------- | ----------- | ----------------------------- | -------------------------------------------------------------- |
| `accountId` | `string` | — | The account id to create. |
| `options.gas` | `bigint` | `300000000000000n` (300 TGas) | Gas attached to the `create_account` call. |
| `options.deposit` | `bigint` | `0n` | NEAR deposit attached to the call. |
| `options.algorithm` | `Algorithm` | `"ed25519"` | Which key algorithm the new account's public key derives from. |
`getPublicKey` parameters:
| Parameter | Type | Default | Description |
| ----------- | ----------- | ----------- | ----------------------------------------------------------------------------------------------------- |
| `algorithm` | `Algorithm` | `"ed25519"` | Selects the key derivation domain. `"ed25519"` maps to domain id `1`, `"secp256k1"` to domain id `0`. |
```ts account.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Derived public key (defaults to ed25519).
const publicKey = await signer.getPublicKey();
const secpKey = await signer.getPublicKey("secp256k1");
// Build (but don't send) an account-creation action.
const action = await signer.createAccount("alice.testnet", {
algorithm: "ed25519",
});
```
### Requesting a signature
These two methods forward to the provider, which drives the user through Auth0 and embeds the encoded transaction into the JWT the guard contract verifies on-chain. Their parameters are inferred from your provider's implementation.
| Method | Signature | Description |
| -------------------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `requestTransactionSignature` | `requestTransactionSignature(...args: Parameters
)` | Requests a signature for a NEAR transaction. Delegates to `provider.requestTransactionSignature(...)`. |
| `requestDelegateActionSignature` | `requestDelegateActionSignature(...args: Parameters
)` | Requests a signature for a delegate action (meta-transaction), enabling relayer-sponsored, gasless flows. Delegates to `provider.requestDelegateActionSignature(...)`. |
| `getSignatureRequest` | `getSignatureRequest(): Promise` | Returns the pending signature request the provider produced after login/redirect. |
With the web provider, requesting a signature typically triggers a popup or redirect to Auth0. Persist any application state you need to survive a full-page redirect before calling these methods.
`getSignatureRequest()` resolves to a `GetSignatureRequestResponse`, which wraps the `SignatureRequest` alongside the resolved user:
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
type GetSignatureRequestResponse = {
user: { userId: string };
signatureRequest: SignatureRequest;
};
type SignatureRequest = {
guardId: string; // JWT guard identifier
verifyPayload: string; // the JWT to verify on-chain
signPayload: Uint8Array; // the transaction bytes to sign
algorithm?: MPCContractAlgorithm; // "secp256k1" | "eddsa" | "ecdsa"
};
```
### Signing and submission
| Method | Signature | Returns | Description |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `createSignAction` | `createSignAction(request: SignatureRequest, options?: CreateSignActionOptions): Promise` | `Promise` | Builds a `sign` function-call `Action` against the NEAR Auth contract from a `SignatureRequest`. Defaults the on-chain algorithm to `"eddsa"` when the request omits one. |
| `sendTransaction` | `sendTransaction(transaction: Transaction, signature: FastAuthSignature, algorithm?: Algorithm): Promise` | `Promise` | Recovers the signature bytes, attaches them to the transaction as a signed transaction, and broadcasts it through the connection's RPC provider. |
`createSignAction` parameters:
| Parameter | Type | Default | Description |
| ----------------- | ------------------ | ----------------------------- | -------------------------------------------------------------------------------- |
| `request` | `SignatureRequest` | — | Contains `guardId`, `verifyPayload`, `signPayload`, and an optional `algorithm`. |
| `options.gas` | `bigint` | `300000000000000n` (300 TGas) | Gas attached to the `sign` call. |
| `options.deposit` | `bigint` | `0n` | NEAR deposit attached to the call. |
`sendTransaction` parameters:
| Parameter | Type | Default | Description |
| ------------- | ------------------- | ----------- | -------------------------------------------------------------------------- |
| `transaction` | `Transaction` | — | The `near-api-js` transaction to sign and broadcast. |
| `signature` | `FastAuthSignature` | — | The MPC signature to attach — see [FastAuthSignature](#fastauthsignature). |
| `algorithm` | `Algorithm` | `"ed25519"` | The algorithm used to recover the signature bytes and pick the key type. |
```ts sign.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
// 1. Read the pending request the provider produced.
const { signatureRequest } = await signer.getSignatureRequest();
// 2. Build the on-chain `sign` action for the NEAR Auth contract.
const signAction = await signer.createSignAction(signatureRequest);
// 3. Submit that action in a transaction to obtain the MPC signature,
// decode it (see FastAuthSignature), then broadcast the real transaction.
const signature = FastAuthSignature.fromBase64(base64Result);
const outcome = await signer.sendTransaction(transaction, signature, "ed25519");
```
***
## FastAuthSignature
A thin wrapper around the raw payload the MPC network returns. It decodes a base64 result and recovers the signature bytes in the exact format `sendTransaction` needs, for either curve.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
class FastAuthSignature
```
### Methods
| Method | Signature | Returns | Description |
| ------------ | ------------------------------------------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `fromBase64` | `static fromBase64(base64Payload: string): FastAuthSignature` | `FastAuthSignature` | Decodes a base64 MPC payload (JSON) into a `FastAuthSignature`. |
| `recover` | `recover(algorithm?: Algorithm): Buffer` | `Buffer` | Recovers the signature bytes for the given curve: 64-byte ed25519 (`R‖S`) or 65-byte secp256k1 (`r‖s‖v`). Defaults to `"ed25519"`. |
`sendTransaction` calls `recover(algorithm)` for you, so you rarely invoke it directly — pass the `FastAuthSignature` straight into `sendTransaction`. Call `recover()` yourself only when you need the raw bytes.
```ts signature.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthSignature } from "@fast-auth-near/browser-sdk";
// Decode the MPC result returned from the `sign` call.
const signature = FastAuthSignature.fromBase64(base64Result);
// Recover raw bytes if you need them directly (defaults to ed25519).
const ed25519Bytes = signature.recover(); // 64 bytes: R‖S
const secp256k1Bytes = signature.recover("secp256k1"); // 65 bytes: r‖s‖v
```
Recovery is algorithm-specific. Pass the same `algorithm` to `recover()` / `sendTransaction()` that the account's key was derived with — an unsupported value throws a signature error.
***
## The `Algorithm` type
The SDK's client-facing algorithm type is:
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
type Algorithm = "secp256k1" | "ed25519";
```
It appears on `getPublicKey`, `createAccount` options, `sendTransaction`, and `FastAuthSignature.recover`, and it defaults to `"ed25519"` everywhere it is optional.
The on-chain `SignatureRequest.algorithm` uses a distinct `MPCContractAlgorithm` = `"secp256k1" | "eddsa" | "ecdsa"` — that is the value the NEAR Auth contract's `sign` method receives. `createSignAction` defaults it to `"eddsa"`. Read more in [How it works](/protocol/how-it-works).
***
## End-to-end example
Putting the three classes together: log in, derive a key, request a signature, then decode and broadcast the result.
```ts full-flow.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthClient, FastAuthSignature } from "@fast-auth-near/browser-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
import { connect } from "near-api-js";
const provider = new JavascriptProvider({
network: "testnet",
clientId: "your-auth0-client-id",
});
const { connection } = await connect({
networkId: "testnet",
nodeUrl: "https://rpc.testnet.near.org",
});
const client = new FastAuthClient(provider, connection, {
fastAuthContractId: "fast-auth.testnet",
mpcContractId: "v1.signer-prod.testnet",
});
// 1. Authenticate and obtain an initialized signer.
await client.login();
const signer = await client.getSigner();
// 2. Derive the user's NEAR public key.
const publicKey = await signer.getPublicKey();
// 3. Ask the provider to embed a transaction into the JWT and sign it.
await signer.requestTransactionSignature(/* provider-specific args */);
const { signatureRequest } = await signer.getSignatureRequest();
// 4. Build the on-chain `sign` action, submit it to get the MPC result,
// then decode and broadcast the final transaction.
const signAction = await signer.createSignAction(signatureRequest);
const signature = FastAuthSignature.fromBase64(base64Result);
const outcome = await signer.sendTransaction(transaction, signature, "ed25519");
```
***
## Next steps
The Auth0 adapter you pair with this SDK — `login`, redirect vs popup, and signature requests.
`IFastAuthProvider`, `SignatureRequest`, `User`, and the shared type surface.
The full signing guide, including relayer-sponsored gasless flows.
From Auth0 JWT to on-chain verification to MPC signature.
Deployed contract ids, RPC endpoints, and network config.
How the SDKs and providers compose across web and mobile.
# Core Types
Source: https://docs.auth.near.org/sdks/core
The shared TypeScript interfaces every NEAR Auth SDK and provider is built on — including IFastAuthProvider, SignatureRequest, and User.
`@shared/core` holds the small set of TypeScript types shared across every NEAR Auth SDK and provider. It defines the contract each provider implements, the shapes returned by login and signature flows, and a handful of network constants.
`@shared/core` is an **internal** package — it is bundled into the published SDKs and providers, not installed on its own. You don't need it for a normal integration. It's documented here because these types are the seam you build against when you write a **custom provider**, or when you want precise types over the values the SDKs hand back.
***
## `IFastAuthProvider`
Every provider — [`JavascriptProvider`](/sdks/javascript-provider), [`ReactNativeProvider`](/sdks/react-native-provider), or one you write yourself — implements this interface. The [browser SDK](/sdks/browser-sdk) and [React SDK](/sdks/react-sdk) accept any `IFastAuthProvider`, so conforming to it is all a custom provider needs to plug into the rest of the stack.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
export interface IFastAuthProvider {
login(...args: any[]): Promise;
logout(...args: any[]): Promise;
isLoggedIn(): Promise;
requestTransactionSignature(...args: any[]): Promise;
requestDelegateActionSignature(...args: any[]): Promise;
getSignatureRequest(): Promise;
getPath(): Promise;
}
```
| Method | Returns | Description |
| ----------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `login(...args)` | `Promise` | Authenticate the user and return their deterministic identifier. |
| `logout(...args)` | `Promise` | Clear the current session. |
| `isLoggedIn()` | `Promise` | Whether a user is currently authenticated. |
| `requestTransactionSignature(...args)` | `Promise` | Ask the identity provider to authorize signing a transaction, embedding the encoded payload in the JWT. |
| `requestDelegateActionSignature(...args)` | `Promise` | Same as above for a delegate action (gasless / meta-transaction). |
| `getSignatureRequest()` | `Promise` | Retrieve the pending [`SignatureRequest`](#signaturerequest) and its user after a signature flow completes. |
| `getPath()` | `Promise` | Return the MPC derivation path for the current identity, of the form `{guardId}#{userSubject}`. |
The `...args: any[]` signatures are intentionally open so each provider can accept its own options (for example the JavaScript provider's popup/redirect flags). Concrete providers narrow these in their own types — see the [JavaScript provider reference](/sdks/javascript-provider) for the real parameters.
***
## Response types
The provider methods resolve to a few thin shapes. `User` is the primitive they all build on.
### `User`
The deterministic identifier for an authenticated identity. The same login always resolves to the same `userId`, which is what lets NEAR Auth derive a stable NEAR key per user.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
export type User = {
userId: string;
};
```
### `LoginResponse`, `RequestTransactionSignatureResponse`, `RequestDelegateActionSignatureResponse`
Each of these is an alias of `User` — login and both signature-request flows resolve to the identity they acted on.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
export type LoginResponse = User;
export type RequestTransactionSignatureResponse = User;
export type RequestDelegateActionSignatureResponse = User;
```
### `GetSignatureRequestResponse`
Returned by `getSignatureRequest()`. Pairs the authenticated `User` with the [`SignatureRequest`](#signaturerequest) the provider prepared for the on-chain `FastAuth.sign` call.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
export type GetSignatureRequestResponse = {
user: User;
signatureRequest: SignatureRequest;
};
```
***
## `SignatureRequest`
The data the SDK feeds into the [NEAR Auth contract](/protocol/contracts/fast-auth)'s `sign` method. Its fields map directly onto the contract's `sign(guard_id, verify_payload, sign_payload, algorithm)` arguments.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
export type SignatureRequest = {
guardId: string;
verifyPayload: string;
signPayload: Uint8Array;
algorithm?: MPCContractAlgorithm;
};
```
The guard identifier — which [JWT guard](/protocol/contracts/jwt-guard-router) verifies this request on-chain (for the Auth0 flow, the [Auth0 guard](/protocol/contracts/auth0-guard)).
The payload to verify — typically the JWT issued by the identity provider, which the guard RS256-verifies before any signature is produced.
The bytes to sign — the encoded transaction or delegate action.
The signing algorithm the MPC network should use. Optional; defaults are resolved downstream.
***
## Constants & unions
### `MPCContractAlgorithm`
The signing algorithms the MPC contract supports.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
export type MPCContractAlgorithm = "secp256k1" | "eddsa" | "ecdsa";
```
This is the on-chain / MPC-facing algorithm union. The SDK-facing signer key type in the [browser SDK](/sdks/browser-sdk) uses `"secp256k1" | "ed25519"` for public keys — they describe different layers, so don't mix them up.
### `FastAuthNetwork`
The two supported NEAR networks. Providers and SDKs take this to select endpoints and defaults.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
export type FastAuthNetwork = "mainnet" | "testnet";
```
### `FAST_AUTH_AUTH0_DEFAULTS`
Per-network Auth0 defaults, keyed by [`FastAuthNetwork`](#fastauthnetwork). Providers fall back to these when you don't pass an explicit `domain` or `signingAudience`.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
export const FAST_AUTH_AUTH0_DEFAULTS: Record = {
mainnet: {
domain: "login.auth.near.org",
audience: "https://api.auth.near.org",
signingAudience: "auth0.jwt.fast-auth.near",
},
testnet: {
domain: "login.testnet.fast-auth.com",
audience: "https://api.testnet.fast-auth.com",
signingAudience: "auth0.jwt.fast-auth.testnet",
},
} as const;
```
The shape of each entry is `FastAuthAuth0NetworkDefaults`:
| Field | Type | Description |
| ----------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `domain` | `string` | The Auth0 tenant domain used for authentication. |
| `audience` | `string` | The Auth0 API audience. |
| `signingAudience` | `string` | The audience embedded in signing JWTs — the [Auth0 guard](/protocol/contracts/auth0-guard) account that must appear in the token's `aud` claim. |
These are the same values documented on the [testnet](/resources/testnet) and [mainnet](/resources/mainnet) resource pages. Read them from `FAST_AUTH_AUTH0_DEFAULTS` instead of hard-coding strings so a network switch stays a one-line change.
***
## Building a custom provider
Because the SDKs depend only on `IFastAuthProvider`, you can implement your own provider — wrapping a different identity source or auth flow — and pass it straight into `FastAuthClient` or `FastAuthProvider`.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import type {
IFastAuthProvider,
LoginResponse,
RequestTransactionSignatureResponse,
RequestDelegateActionSignatureResponse,
GetSignatureRequestResponse,
} from "@shared/core";
class MyProvider implements IFastAuthProvider {
async login(): Promise {
// authenticate the user, then return their deterministic id
return { userId: "..." };
}
async logout(): Promise {
// clear the session
}
async isLoggedIn(): Promise {
return false;
}
async requestTransactionSignature(): Promise {
return { userId: "..." };
}
async requestDelegateActionSignature(): Promise {
return { userId: "..." };
}
async getSignatureRequest(): Promise {
return {
user: { userId: "..." },
signatureRequest: {
guardId: "auth0",
verifyPayload: "",
signPayload: new Uint8Array(),
},
};
}
async getPath(): Promise {
return "auth0#user-subject";
}
}
```
Writing a custom provider for a **different identity issuer** touches on-chain territory — a matching guard has to verify your JWTs. That's an advanced topic outside the Auth0 happy path; see [Protocol → Advanced → Custom issuer](/protocol/advanced/custom-issuer) and [Custom issuer guard](/protocol/advanced/custom-issuer-guard) before you go down this road.
***
## Next steps
How the SDKs, providers, and core types fit together.
The reference `IFastAuthProvider` implementation for web.
`FastAuthClient` and `FastAuthSigner`, built on these types.
Where a `SignatureRequest` goes once it leaves the SDK.
# JavaScript Provider
Source: https://docs.auth.near.org/sdks/javascript-provider
Full reference for the JavascriptProvider — Auth0 login and signature requests for web apps, using popup or redirect flows.
`@fast-auth-near/javascript-provider` is the web provider for NEAR Auth. It wraps Auth0's single-page-app client to authenticate users and request signatures over their NEAR account, then hands those requests to a NEAR Auth SDK to submit on-chain. It exposes a single class, `JavascriptProvider`, which implements the shared `IFastAuthProvider` interface.
A provider on its own only handles the Auth0 side — login, logout, and building the signature request. You inject it into a `FastAuthClient` from the [Browser SDK](/sdks/browser-sdk) or the [React SDK](/sdks/react-sdk), which take care of key derivation, on-chain verification, and MPC signing.
Pair this provider with the framework-agnostic `FastAuthClient`.
Use it through `FastAuthProvider` and hooks in a React app.
***
## Installation
Install the provider alongside the SDK you plan to inject it into.
```bash npm theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/javascript-provider
```
```bash yarn theme={"theme":{"light":"github-light","dark":"github-dark"}}
yarn add @fast-auth-near/javascript-provider
```
```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark"}}
pnpm add @fast-auth-near/javascript-provider
```
The provider ships with `@auth0/auth0-spa-js`, `near-api-js`, and `@near-js/transactions` as dependencies, which are installed automatically.
***
## Create a provider
The constructor takes your network and Auth0 client ID. Everything else — the Auth0 `domain` and the `signingAudience` used for signature requests — defaults to the shared NEAR Auth values for that network, so a typical setup is two lines.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
const provider = new JavascriptProvider({
network: "testnet",
clientId: "np8paqIpMWmNbzT4xAvOOapZBjsOpptl",
});
```
The client IDs above and below are the shared NEAR Auth testnet and mainnet Auth0 applications. You can build against testnet immediately; when you're ready for production, [apply for mainnet access](/home/apply).
### Constructor options
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
new JavascriptProvider(options: JavascriptProviderOptions)
```
| Option | Type | Required | Description |
| ----------------- | ------------------------ | -------- | -------------------------------------------------------------------------------------------- |
| `network` | `"mainnet" \| "testnet"` | Yes | Selects the NEAR Auth network and the default Auth0 `domain` / `signingAudience`. |
| `clientId` | `string` | Yes | Your Auth0 application client ID. |
| `domain` | `string` | No | Auth0 tenant domain. Defaults to the network's NEAR Auth domain (see below). |
| `signingAudience` | `string` | No | Auth0 audience requested when signing. Defaults to the network's NEAR Auth signing audience. |
### Network defaults
When you omit `domain` and `signingAudience`, the provider fills them from the network defaults:
| Network | `domain` | `signingAudience` | Shared `clientId` |
| --------- | ----------------------------- | ----------------------------- | ---------------------------------- |
| `mainnet` | `login.auth.near.org` | `auth0.jwt.fast-auth.near` | `dsurLc47fOcWme5PkYeClBvuW0tYrmgW` |
| `testnet` | `login.testnet.fast-auth.com` | `auth0.jwt.fast-auth.testnet` | `np8paqIpMWmNbzT4xAvOOapZBjsOpptl` |
Only override `domain` and `signingAudience` if you run your own Auth0 tenant and NEAR Auth deployment. For the default Auth0 login, the two required fields are enough.
***
## Methods
`JavascriptProvider` implements `IFastAuthProvider`. Signature methods return the authenticated `User` (`{ userId }`), except `isLoggedIn` and `getPath`.
### `login(options?, forceSelectAccount?)`
Signs the user in through Auth0 and resolves to the authenticated `User`.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
login(
options?: JavascriptLoginOptions,
forceSelectAccount?: boolean,
): Promise<{ userId: string }>
```
The flow is chosen by whether `options` contains a `redirectUri`:
* **Popup** — call `login()` with no options (or popup options without a `redirectUri`). Auth0 opens in a popup and the promise resolves in the same page.
* **Redirect** — pass `{ redirectUri }`. The browser navigates to Auth0 and back to `redirectUri`; on return, call [`isLoggedIn()`](#isloggedin) to complete the callback.
`forceSelectAccount: true` sets the Auth0 `prompt` to `"login"`, forcing the user to re-authenticate instead of resuming an existing session.
| Parameter | Type | Description |
| ---------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `options.redirectUri` | `string` | Present → redirect flow, and the URL Auth0 returns to. Absent → popup flow. |
| `options` (other keys) | `RedirectLoginOptions` / `PopupLoginOptions` | Any other `@auth0/auth0-spa-js` login option except `authorizationParams`, which the provider manages. |
| `forceSelectAccount` | `boolean` | Force re-authentication with the Auth0 login prompt. |
```ts popup.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Popup flow (default): resolves in the current page.
const user = await provider.login();
console.log(user.userId);
```
```ts redirect.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Redirect flow: navigates away to Auth0 and back.
await provider.login({ redirectUri: window.location.origin });
// Force the user to re-authenticate.
await provider.login({ redirectUri: window.location.origin }, true);
```
Popup login can be blocked by browser pop-up blockers unless it runs from a direct user gesture such as a button click. If you can't guarantee a gesture, prefer the redirect flow.
### `logout(options?)`
Logs the user out and clears the Auth0 session. Accepts the standard `@auth0/auth0-spa-js` `LogoutOptions` (for example a `logoutParams.returnTo` URL).
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
logout(options?: LogoutOptions): Promise
```
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
await provider.logout();
// Optionally return to a specific URL after logout.
await provider.logout({ logoutParams: { returnTo: window.location.origin } });
```
### `isLoggedIn()`
Returns whether the user is authenticated. It also completes the Auth0 redirect callback: if the current URL carries the `code` and `state` query parameters from a redirect login, it exchanges them before reporting status. Call it on page load to finish redirect-based logins.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
isLoggedIn(): Promise
```
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
if (await provider.isLoggedIn()) {
console.log("User is authenticated");
}
```
### `getPath()`
Returns the NEAR Auth path identifier for the signed-in user, in the form `jwt#https://{domain}/#{sub}`, where `sub` is the Auth0 subject. Throws `JavascriptProviderError` with code `USER_NOT_LOGGED_IN` if there is no authenticated session.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
getPath(): Promise
```
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
const path = await provider.getPath();
// e.g. "jwt#https://login.testnet.fast-auth.com/#google-oauth2|1234567890"
```
### `requestTransactionSignature({ transaction, redirectUri? })`
Asks Auth0 to approve a NEAR transaction. The provider Borsh-encodes the transaction and embeds it in the sign request, then routes through popup or redirect just like `login`. Resolves to the authenticated `User`.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
requestTransactionSignature(
options: JavascriptRequestTransactionSignatureOptions,
): Promise<{ userId: string }>
```
| Parameter | Type | Description |
| ------------- | -------------------------------------------- | -------------------------------------------------------------------------- |
| `transaction` | `Transaction` (`near-api-js`) | The NEAR transaction to sign. |
| `redirectUri` | `string` (optional) | Present → redirect flow. Absent → popup flow. |
| (other keys) | `RedirectLoginOptions` / `PopupLoginOptions` | Any other `@auth0/auth0-spa-js` login option except `authorizationParams`. |
After the approval completes, read the resulting request with [`getSignatureRequest()`](#getsignaturerequest).
```ts popup.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { Transaction } from "near-api-js/lib/transaction";
// Popup: no redirectUri.
await provider.requestTransactionSignature({ transaction });
const { signatureRequest } = await provider.getSignatureRequest();
```
```ts redirect.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { Transaction } from "near-api-js/lib/transaction";
// Redirect: pass a redirectUri to return to after approval.
await provider.requestTransactionSignature({
transaction,
redirectUri: window.location.origin + "/callback",
});
```
### `requestDelegateActionSignature({ delegateAction, redirectUri? })`
Same as `requestTransactionSignature`, but for a NEAR delegate action — the meta-transaction shape a relayer submits to sponsor gas. The provider encodes the delegate action and requests approval over popup or redirect. Resolves to the authenticated `User`.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
requestDelegateActionSignature(
options: JavascriptRequestDelegateActionSignatureOptions,
): Promise<{ userId: string }>
```
| Parameter | Type | Description |
| ---------------- | -------------------------------------------- | -------------------------------------------------------------------------- |
| `delegateAction` | `DelegateAction` (`@near-js/transactions`) | The delegate action to sign. |
| `redirectUri` | `string` (optional) | Present → redirect flow. Absent → popup flow. |
| (other keys) | `RedirectLoginOptions` / `PopupLoginOptions` | Any other `@auth0/auth0-spa-js` login option except `authorizationParams`. |
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { DelegateAction } from "@near-js/transactions";
await provider.requestDelegateActionSignature({ delegateAction });
const { signatureRequest } = await provider.getSignatureRequest();
```
Delegate actions are how NEAR Auth enables gasless transactions: a relayer wraps the signed delegate action in a meta-transaction and pays the gas. See [Sign transactions](/home/guides/sign-transactions) for the end-to-end flow.
### `getSignatureRequest()`
Reads the approved signature request out of the Auth0 token after a signing approval. It fetches the token silently for the configured `signingAudience`, decodes the embedded payload, and returns both the `User` and the `SignatureRequest`.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
getSignatureRequest(): Promise<{ user: User; signatureRequest: SignatureRequest }>
```
The returned `signatureRequest` is what a NEAR Auth SDK forwards on-chain:
| Field | Type | Description |
| --------------- | ---------------------------------------------- | --------------------------------------------------------- |
| `guardId` | `string` | The guard identifier, `jwt#https://{domain}/`. |
| `verifyPayload` | `string` | The Auth0 JWT the guard verifies on-chain. |
| `signPayload` | `Uint8Array` | The encoded transaction or delegate-action bytes to sign. |
| `algorithm` | `"secp256k1" \| "eddsa" \| "ecdsa"` (optional) | The signing algorithm, when set. |
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
const { user, signatureRequest } = await provider.getSignatureRequest();
console.log(user.userId);
console.log(signatureRequest.guardId);
```
In practice you rarely call `getSignatureRequest()` yourself — the SDK reads it for you when you sign through `FastAuthSigner`. It's exposed here for advanced flows and debugging.
***
## Error handling
The provider throws `JavascriptProviderError` for provider-level failures. Today it carries a single code, `USER_NOT_LOGGED_IN`, thrown by `getPath()` (and internally when reading the user's subject) if no user is authenticated.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import {
JavascriptProviderError,
JavascriptProviderErrorCodes,
} from "@fast-auth-near/javascript-provider";
try {
const path = await provider.getPath();
} catch (error) {
if (
error instanceof JavascriptProviderError &&
error.message === JavascriptProviderErrorCodes.USER_NOT_LOGGED_IN
) {
console.log("Please log in first");
}
}
```
***
## Full example
A minimal popup-based integration with the Browser SDK: create the provider, wire it into a `FastAuthClient`, log in, and get a signer.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthClient } from "@fast-auth-near/browser-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
import { connect } from "near-api-js";
const provider = new JavascriptProvider({
network: "testnet",
clientId: "np8paqIpMWmNbzT4xAvOOapZBjsOpptl",
});
const { connection } = await connect({
networkId: "testnet",
nodeUrl: "https://rpc.testnet.near.org",
});
const client = new FastAuthClient(provider, connection, {
fastAuthContractId: "fast-auth.testnet",
mpcContractId: "v1.signer-prod.testnet",
});
await client.login();
const signer = await client.getSigner();
```
***
## Next steps
The `FastAuthClient` and `FastAuthSigner` you inject this provider into.
Use the provider through `FastAuthProvider` and hooks.
Login, logout, and session handling end to end.
Request signatures and submit transactions, optionally gasless.
Domains, audiences, and contract ids per network.
Which library fits your stack.
# SDKs overview
Source: https://docs.auth.near.org/sdks/overview
The NEAR Auth library landscape — SDKs, platform providers, and shared core, and how they compose.
NEAR Auth ships as a small family of TypeScript packages. An **SDK** gives you the `FastAuthClient` and `FastAuthSigner` classes that log users in and turn NEAR transactions into MPC-backed signatures. A **provider** is the platform adapter that actually talks to Auth0 — one for the web, one for React Native. You pick one SDK for your framework and one provider for your platform, and compose them.
Everything is published under the `@fast-auth-near/*` scope on npm and lives in [`github.com/Peersyst/fast-auth`](https://github.com/Peersyst/fast-auth).
***
## The packages at a glance
| Package | Layer | Platform | When to use |
| --------------------------------------- | -------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `@fast-auth-near/react-sdk` | SDK | React (web) | React apps — provider component plus `useFastAuth`, `useSigner`, `useIsLoggedIn`, `usePublicKey` hooks and a relayer-aware client. |
| `@fast-auth-near/browser-sdk` | SDK | Any web framework | Vanilla JS, Vue, Svelte, Angular — the framework-agnostic `FastAuthClient` / `FastAuthSigner` classes. |
| `@fast-auth-near/javascript-provider` | Provider | Web browsers | Pair with either web SDK to run the Auth0 flow via popup or redirect. |
| `@fast-auth-near/react-native-provider` | Provider | iOS & Android | Pair with the React SDK to run the Auth0 flow with native mobile screens. |
| `@shared/core` | Core | Shared | Internal shared types — `IFastAuthProvider`, `SignatureRequest`, `User`, and network defaults consumed by every package. |
`FastAuthProvider`, hooks, and the relayer-backed signer for React apps.
The framework-agnostic `FastAuthClient` and `FastAuthSigner` classes.
`JavascriptProvider` — the Auth0 adapter for web, popup or redirect.
`ReactNativeProvider` — the Auth0 adapter for iOS and Android.
`IFastAuthProvider`, `SignatureRequest`, and the shared type surface.
***
## The SDK + provider composition model
NEAR Auth splits **what to do** from **how to authenticate**. The SDK owns the NEAR-facing work — deriving the user's public key, building transactions, requesting MPC signatures, and (in the React SDK) coordinating a relayer. The provider owns the identity work — opening the Auth0 login screen, holding the session, and embedding the encoded transaction into the JWT the guard contract verifies on-chain.
The two meet at a single contract: every provider implements the `IFastAuthProvider` interface from `@shared/core`.
```ts IFastAuthProvider theme={"theme":{"light":"github-light","dark":"github-dark"}}
export interface IFastAuthProvider {
login(...args: any[]): Promise;
logout(...args: any[]): Promise;
isLoggedIn(): Promise;
requestTransactionSignature(...args: any[]): Promise;
requestDelegateActionSignature(...args: any[]): Promise;
getSignatureRequest(): Promise;
getPath(): Promise;
}
```
Because the SDK only depends on this interface, swapping platforms is a matter of swapping the provider you pass in. You construct a provider, hand it to the SDK, and the rest of your code is identical across web and mobile.
```ts browser-sdk.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthClient } from "@fast-auth-near/browser-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
// 1. Build a provider for your platform (web = JavascriptProvider).
const provider = new JavascriptProvider({
network: "testnet",
clientId: "your-auth0-client-id",
});
// 2. Hand it to the SDK. The client only knows IFastAuthProvider.
const client = new FastAuthClient(provider, connection, {
fastAuthContractId: "fast-auth.testnet",
mpcContractId: "v1.signer-prod.testnet",
});
await client.login();
const signer = await client.getSigner();
```
```tsx react-sdk.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthProvider } from "@fast-auth-near/react-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
// Same provider, wrapped by the React SDK's context provider.
const provider = new JavascriptProvider({
network: "testnet",
clientId: "your-auth0-client-id",
});
export default function App({ connection }) {
return (
{/* useFastAuth(), useSigner(), useIsLoggedIn()… */}
);
}
```
A provider carries the authentication flow; an SDK carries the NEAR flow. You always need one of each — one SDK for your framework and one provider for your platform.
***
## Which combination fits your stack
Use the **React SDK** with the **JavaScript provider**. You get the `FastAuthProvider` context, hooks, and a relayer-backed signer that exposes `signAndSendTransaction(...)` and `signAndSendDelegateAction(...)`.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/react-sdk @fast-auth-near/javascript-provider near-api-js
```
Use the **Browser SDK** with the **JavaScript provider** for vanilla JS, Vue, Svelte, or Angular — a class-based API with full control over the flow.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/browser-sdk @fast-auth-near/javascript-provider near-api-js
```
Use the **React SDK** with the **React Native provider** to bring the same login to iOS and Android with native screens and secure credential storage.
```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/react-sdk @fast-auth-near/react-native-provider
```
Not sure yet? The [choose your SDK](/home/guides/choose-your-sdk) guide walks through the decision for your framework and platform.
***
## Providers beyond Auth0
Auth0 is the default identity provider across NEAR Auth, and both the JavaScript and React Native providers use it out of the box. Other identity setups — such as a custom issuer — are handled at the protocol layer by dedicated guard contracts rather than by these SDKs.
Non-Auth0 identity setups are an advanced path with their own guard contract and key-management model. They are covered under [Protocol → Advanced](/protocol/advanced/custom-issuer-guard), not here.
***
## Next steps
Log in and sign a testnet transaction in under five minutes.
Login, logout, and session handling with the SDK of your choice.
Request signatures and submit NEAR transactions, optionally gasless.
The end-to-end Auth0 flow, from JWT to MPC signature.
# React Native Provider
Source: https://docs.auth.near.org/sdks/react-native-provider
Native mobile Auth0 login and NEAR signature requests for React Native, backed by react-native-auth0.
The `@fast-auth-near/react-native-provider` package ships `ReactNativeProvider`, the mobile identity provider for NEAR Auth. It adapts [`react-native-auth0`](https://github.com/auth0/react-native-auth0) to the shared provider interface so your iOS and Android app can authenticate users with Auth0 and request NEAR signatures using the platform's native Web Authentication browser.
Like every provider, it implements `IFastAuthProvider` and is designed to be injected into a `FastAuthClient` from the [React SDK](/sdks/react-sdk). The provider handles Auth0 login and signature requests; the SDK handles NEAR account and transaction plumbing.
This is the mobile counterpart of the [JavaScript provider](/sdks/javascript-provider). It exposes the same method surface but authenticates through the native Auth0 SDK instead of a web popup or redirect. See [Key differences](#key-differences-vs-the-javascript-provider) below.
***
## Installation
```bash npm theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/react-native-provider
```
```bash yarn theme={"theme":{"light":"github-light","dark":"github-dark"}}
yarn add @fast-auth-near/react-native-provider
```
```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark"}}
pnpm add @fast-auth-near/react-native-provider
```
The package depends on `react-native-auth0`, `near-api-js`, `@near-js/transactions`, and `jose`. It requires `react` (>=16.8.0) and `react-native` (>=0.60.0) as peer dependencies.
`react-native-auth0` includes native modules. After installing, run `pod install` in your `ios/` directory and configure your Auth0 callback URLs for iOS and Android per the [react-native-auth0 setup guide](https://github.com/auth0/react-native-auth0#getting-started). Login opens the system browser, so both platforms must register the app's URL scheme.
***
## Constructor
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { ReactNativeProvider } from "@fast-auth-near/react-native-provider";
const provider = new ReactNativeProvider({
network: "testnet",
clientId: "your-auth0-client-id",
});
```
`ReactNativeProvider` takes a single options object. Only `network` and `clientId` are required — `domain` and `signingAudience` fall back to the NEAR Auth defaults for the chosen network.
The NEAR network to target. Selects the default Auth0 `domain` and `signingAudience` for that network.
Your Auth0 application client ID.
The Auth0 domain. Defaults to `login.auth.near.org` on mainnet and `login.testnet.fast-auth.com` on testnet.
The Auth0 API audience used when requesting signature tokens. Defaults to `auth0.jwt.fast-auth.near` on mainnet and `auth0.jwt.fast-auth.testnet` on testnet.
Internally the constructor resolves these options against `FAST_AUTH_AUTH0_DEFAULTS[network]` and instantiates the underlying `Auth0` client with the resolved `domain` and `clientId`.
### Network defaults
| Network | `domain` | `signingAudience` |
| --------- | ----------------------------- | ----------------------------- |
| `mainnet` | `login.auth.near.org` | `auth0.jwt.fast-auth.near` |
| `testnet` | `login.testnet.fast-auth.com` | `auth0.jwt.fast-auth.testnet` |
On testnet you can use the shared NEAR Auth Auth0 client ID `np8paqIpMWmNbzT4xAvOOapZBjsOpptl` to start building immediately — no sign-off required. When you are ready for mainnet, [apply for production access](/home/apply).
***
## Setup with ``
`react-native-auth0` requires an `Auth0Provider` context around your component tree. The package re-exports `Auth0Provider` for convenience, so you can wrap your app and construct the `ReactNativeProvider` in one place.
```tsx App.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { Auth0Provider, ReactNativeProvider } from "@fast-auth-near/react-native-provider";
const provider = new ReactNativeProvider({
network: "testnet",
clientId: "your-auth0-client-id",
});
export default function App() {
return (
);
}
```
The `domain` and `clientId` you pass to `` must match the ones the `ReactNativeProvider` resolves, so both talk to the same Auth0 tenant.
### Using it with the React SDK
To drive the provider through the [React SDK](/sdks/react-sdk) hooks, use the `reactNativeProviderConfig` helper. It returns both the provider instance and a `reactProvider` render function that wraps children in the correct `` for you — pass the whole config straight to `FastAuthProvider`.
```tsx App.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthProvider } from "@fast-auth-near/react-sdk";
import { reactNativeProviderConfig } from "@fast-auth-near/react-native-provider";
import { Connection } from "near-api-js";
const connection = new Connection({
networkId: "testnet",
provider: {
type: "JsonRpcProvider",
args: { url: "https://rpc.testnet.near.org" },
},
});
const providerConfig = reactNativeProviderConfig({
network: "testnet",
clientId: "your-auth0-client-id",
});
export default function App() {
return (
);
}
```
`reactNativeProviderConfig` accepts the same options as the constructor and returns `{ provider, reactProvider }`. From there, use `useFastAuth`, `useIsLoggedIn`, and `useSigner` exactly as documented in the [React SDK reference](/sdks/react-sdk).
***
## Methods
`ReactNativeProvider` exposes the full `IFastAuthProvider` surface. Every method is asynchronous.
| Method | Purpose |
| ---------------------------------------------------- | ------------------------------------------------------------------- |
| `login(forceSelectAccount?)` | Sign in via native Web Authentication and persist the session. |
| `logout()` | Clear the remote Auth0 session and local credentials. |
| `isLoggedIn()` | Check whether valid, unexpired session credentials exist. |
| `getPath()` | Return the NEAR Auth path derived from the session subject. |
| `requestTransactionSignature({ transaction })` | Open an authorization flow to approve signing a transaction. |
| `requestDelegateActionSignature({ delegateAction })` | Open an authorization flow to approve signing a delegate action. |
| `getSignatureRequest()` | Consume the one-shot signing credentials into a `SignatureRequest`. |
### `login`
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
login(forceSelectAccount?: boolean): Promise
```
Starts the native Web Authentication flow in the system browser. On success it decodes the subject (`sub`) from the returned credentials and persists the session through the Auth0 `credentialsManager`, so the user stays signed in across app launches. Resolves to a `LoginResponse` (`{ userId }`).
Pass `forceSelectAccount: true` to send Auth0 `prompt=login`, forcing the account picker instead of silently reusing an existing session.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Standard login (reuses an existing Auth0 session if present)
const { userId } = await provider.login();
// Force the user to re-select an account
await provider.login(true);
```
### `logout`
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
logout(): Promise
```
Clears the in-memory signing credentials, then clears the remote Auth0 session and the persisted session credentials.
If clearing the remote Auth0 session fails, `logout` still clears the local credentials and then re-throws the error. Wrap the call in `try/catch` if you want to surface remote sign-out failures to the user — the device is logged out regardless.
### `isLoggedIn`
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
isLoggedIn(): Promise
```
Returns `true` only when the `credentialsManager` holds credentials whose `expiresAt` is still in the future. Any error while reading credentials resolves to `false`, so this is safe to call on startup.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
if (await provider.isLoggedIn()) {
// show the authenticated experience
}
```
### `getPath`
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
getPath(): Promise
```
Returns the NEAR Auth path for the signed-in user, built from the session ID token's subject and the Auth0 domain:
```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
jwt#https://{domain}/#${sub}
```
This is the deterministic identifier NEAR Auth uses to derive the user's key. Throws a `ReactNativeProviderError` with code `CREDENTIALS_NOT_FOUND` when there is no session ID token.
### `requestTransactionSignature`
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
requestTransactionSignature(
options: { transaction: Transaction }
): Promise
```
Encodes the NEAR `Transaction`, then opens a fresh Web Authentication flow against the `signingAudience` with scope `transaction:sign`, embedding the encoded transaction as an authorization parameter. The resulting signing token is held **in memory only** — it does not touch the persisted session — and is decoded by [`getSignatureRequest`](#getsignaturerequest). Resolves to the authenticated `{ userId }`.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { Transaction } from "near-api-js/lib/transaction";
await provider.requestTransactionSignature({ transaction });
const { signatureRequest } = await provider.getSignatureRequest();
```
Options are passed directly — there is no wrapping `options` key. Pass `{ transaction }`, not `{ options: { transaction } }`.
### `requestDelegateActionSignature`
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
requestDelegateActionSignature(
options: { delegateAction: DelegateAction }
): Promise
```
Identical to `requestTransactionSignature` but for a [`DelegateAction`](/home/guides/sign-transactions) (the meta-transaction submitted through a relayer for gasless signing). It encodes the delegate action, opens the signing flow against the `signingAudience` with scope `transaction:sign`, and keeps the signing token in memory for `getSignatureRequest` to consume.
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { DelegateAction } from "@near-js/transactions";
await provider.requestDelegateActionSignature({ delegateAction });
const { signatureRequest } = await provider.getSignatureRequest();
```
### `getSignatureRequest`
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
getSignatureRequest(): Promise<{ user: User; signatureRequest: SignatureRequest }>
```
Consumes the in-memory signing credentials produced by the last `requestTransactionSignature` or `requestDelegateActionSignature` call and returns the `SignatureRequest` your app submits on-chain:
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
interface SignatureRequest {
guardId: string; // `jwt#https://{domain}/`
verifyPayload: string; // the signing access token (JWT with the fatxn claim)
signPayload: Uint8Array; // the encoded transaction / delegate action to sign
}
```
It also returns the resolved `user` (`{ userId }`) from the token's subject.
The signing credentials are **one-shot**. `getSignatureRequest` reads them, then sets the in-memory credentials back to `null`. Call it exactly once per signature request — a second call before the next `request*Signature` throws `CREDENTIALS_NOT_FOUND`. It also throws `CREDENTIALS_NOT_FOUND` if no signing flow has been run yet.
***
## Key differences vs the JavaScript provider
Both providers implement `IFastAuthProvider` and expose the same methods, so you can swap platforms with minimal code changes. The behavioral differences come from mobile Auth0:
Login always uses the system browser via `react-native-auth0`. There is no popup-vs-redirect choice like on web — the [JavaScript provider](/sdks/javascript-provider) exposes both.
Session credentials are stored by the Auth0 `credentialsManager`, so users stay signed in across app restarts without re-authenticating.
Signing tokens are kept in memory and consumed once by `getSignatureRequest`. They never touch the persisted session, and a second read throws.
Signature methods take `{ transaction }` / `{ delegateAction }` directly. There is no `redirectUri` option, since mobile does not redirect the way the web provider can.
***
## Error handling
Provider failures throw a `ReactNativeProviderError` carrying a typed code. Import both to branch on the failure reason:
```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import {
ReactNativeProviderError,
ReactNativeProviderErrorCodes,
} from "@fast-auth-near/react-native-provider";
try {
const path = await provider.getPath();
} catch (error) {
if (error instanceof ReactNativeProviderError) {
switch (error.message) {
case ReactNativeProviderErrorCodes.CREDENTIALS_NOT_FOUND:
// no session or signing credentials available
break;
case ReactNativeProviderErrorCodes.INVALID_SUB:
// the token is missing a subject claim
break;
}
}
}
```
| Code | Meaning |
| ----------------------- | ------------------------------------------------------------------ |
| `USER_NOT_LOGGED_IN` | An operation needed an authenticated user but none was present. |
| `CREDENTIALS_NOT_FOUND` | No session or signing credentials were found in storage or memory. |
| `INVALID_SUB` | The token did not contain a valid `sub` (subject) claim. |
| `INVALID_TOKEN` | The token was malformed or could not be decoded. |
***
## Full example
```tsx App.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { Auth0Provider, ReactNativeProvider } from "@fast-auth-near/react-native-provider";
import { Transaction } from "near-api-js/lib/transaction";
import { Button, View } from "react-native";
import { useCallback } from "react";
const provider = new ReactNativeProvider({
network: "testnet",
clientId: "your-auth0-client-id",
});
function Screen() {
const signIn = useCallback(async () => {
await provider.login();
}, []);
const sign = useCallback(async (transaction: Transaction) => {
await provider.requestTransactionSignature({ transaction });
const { signatureRequest } = await provider.getSignatureRequest();
// submit signatureRequest on-chain via the React SDK's FastAuthClient
return signatureRequest;
}, []);
return (
);
}
export default function App() {
return (
);
}
```
***
## Next steps
Inject this provider into `FastAuthClient` and drive it with hooks.
The web counterpart with popup and redirect login.
Login, logout, and session handling end to end.
Turn a signature request into a submitted NEAR transaction.
See how the providers and SDKs fit different stacks.
Browse every published NEAR Auth library.
# React SDK
Source: https://docs.auth.near.org/sdks/react-sdk
Full reference for the NEAR Auth React SDK — the FastAuthProvider, hooks, and the relayer-backed client and signer.
The React SDK is the fastest way to add NEAR Auth to a React app. It ships a single `` that wires up a relayer-backed `FastAuthClient`, plus a set of hooks (`useFastAuth`, `useSigner`, `useIsLoggedIn`, `usePublicKey`) that manage loading and error state for you. Under the hood the client and signer delegate to an auth provider — [`JavascriptProvider`](/sdks/javascript-provider) on web, [`ReactNativeProvider`](/sdks/react-native-provider) on mobile — for the Auth0 login and signature flow.
This SDK re-exports the framework-agnostic core (`FastAuthClient`, `FastAuthSigner`, `FastAuthSignature`) documented in the [Browser SDK](/sdks/browser-sdk). The React variants add automatic per-network contract configuration and relayer support, so you rarely touch the classes directly — the hooks do it for you.
***
## Installation
The SDK requires React 19 and `near-api-js` as peer dependencies. Install it alongside `near-api-js` and the auth provider for your platform.
```bash npm theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @fast-auth-near/react-sdk near-api-js
```
```bash yarn theme={"theme":{"light":"github-light","dark":"github-dark"}}
yarn add @fast-auth-near/react-sdk near-api-js
```
```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark"}}
pnpm add @fast-auth-near/react-sdk near-api-js
```
| Peer dependency | Version | Why |
| --------------- | --------- | --------------------------------------------------- |
| `react` | `^19.0.0` | The SDK is built on React 19 hooks and context. |
| `near-api-js` | latest | Supplies the `Connection` used to talk to NEAR RPC. |
Then add the web auth provider (`@fast-auth-near/javascript-provider`) or the mobile one (`@fast-auth-near/react-native-provider`) depending on your target. See [Choose your SDK](/home/guides/choose-your-sdk) if you are unsure which one fits your stack.
***
## ``
Wrap your app once, near the root. The provider constructs a `FastAuthClient` from your auth provider, NEAR connection, and target network, then exposes it to the tree via context. Every hook in this SDK must be rendered inside it.
```tsx App.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthProvider } from "@fast-auth-near/react-sdk";
import { JavascriptProvider } from "@fast-auth-near/javascript-provider";
import { connect } from "near-api-js";
const provider = new JavascriptProvider({
network: "testnet",
clientId: "your-auth0-client-id",
});
const { connection } = await connect({
networkId: "testnet",
nodeUrl: "https://rpc.testnet.near.org",
});
export default function App() {
return (
);
}
```
### Props
| Prop | Type | Required | Description |
| ---------------- | ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `providerConfig` | `FastAuthProviderConfig` | Yes | The auth provider plus an optional React wrapper. See the breakdown below. |
| `connection` | `Connection` | Yes | A `near-api-js` connection pointed at your NEAR RPC. It backs all read/submit calls. |
| `network` | `"mainnet" \| "testnet"` | Yes | Selects the network. NEAR Auth automatically resolves the matching contract addresses from this value — you do not pass contract ids. |
| `children` | `ReactNode` | Yes | Your application tree. |
### `providerConfig`
| Field | Type | Required | Description |
| --------------- | ------------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider` | `IFastAuthProvider` | Yes | The auth provider instance — typically a `JavascriptProvider` (web) or `ReactNativeProvider` (mobile). It handles login, logout, and signature requests. |
| `reactProvider` | `(children: ReactNode) => ReactNode` | No | An optional wrapper that mounts a React context around your tree. Use it when the auth provider needs its own React provider — for example wrapping in `Auth0Provider` from `react-native-auth0`. Defaults to passing `children` through unchanged. |
Some providers ship their own React context. `reactProvider` lets you mount it without leaving `FastAuthProvider`. On React Native, wrap the tree in `Auth0Provider` so `ReactNativeProvider` can reach the native SDK:
```tsx App.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { FastAuthProvider } from "@fast-auth-near/react-sdk";
import { ReactNativeProvider } from "@fast-auth-near/react-native-provider";
import { Auth0Provider } from "react-native-auth0";
const provider = new ReactNativeProvider({
network: "testnet",
clientId: "your-auth0-client-id",
});
(
{children}
),
}}
connection={connection}
network="testnet"
>
;
```
### Network defaults
The `network` prop is the single source of truth for which contracts NEAR Auth talks to. You never wire contract ids by hand in the React SDK.
| `network` | NEAR Auth contract | MPC contract |
| ----------- | ---------------------------- | ------------------------ |
| `"testnet"` | `fast-auth-beta-001.testnet` | `v1.signer-prod.testnet` |
| `"mainnet"` | `fast-auth.near` | `v1.signer` |
Make sure `network` matches the `network` you passed to your auth provider and the `networkId` of your `Connection`. Mixing testnet and mainnet across the three will produce signatures against the wrong contracts.
***
## Hooks
All hooks read from `FastAuthProvider`'s context, so they only work inside the provider. Each data hook (`useSigner`, `useIsLoggedIn`, `usePublicKey`) follows the same shape: it returns the resolved value plus `isLoading`, `error`, and a `refetch` function, and by default fetches automatically once the client is ready. Pass `false` to the auto-fetch flag to fetch manually via `refetch`.
### `useFastAuth`
The root hook. It returns the client and a ready flag; every other hook is built on top of it. Throws if rendered outside a `FastAuthProvider`.
```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
function useFastAuth
\| null` | The client instance. `null` until the provider finishes initializing. |
| `isReady` | `boolean` | `true` once the client is constructed and safe to call. |
```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { useFastAuth } from "@fast-auth-near/react-sdk";
function AuthButtons() {
const { client, isReady } = useFastAuth();
if (!isReady || !client) return
Initializing…
;
return (
<>
>
);
}
```
### `useIsLoggedIn`
Checks the current authentication status through the client's provider, tracking loading and error state.
```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
function useIsLoggedIn
(
autoCheck?: boolean,
): {
isLoggedIn: boolean | null;
isLoading: boolean;
error: Error | null;
refetch: () => Promise;
};
```
| Param | Type | Default | Description |
| ----------- | --------- | ------- | --------------------------------------------------------------------- |
| `autoCheck` | `boolean` | `true` | Whether to check login status automatically once the client is ready. |
| Return field | Type | Description |
| ------------ | --------------------- | ------------------------------------------------------- |
| `isLoggedIn` | `boolean \| null` | `true`, `false`, or `null` if the check hasn't run yet. |
| `isLoading` | `boolean` | `true` while the check is in flight. |
| `error` | `Error \| null` | The error if the check failed, otherwise `null`. |
| `refetch` | `() => Promise` | Re-runs the login-status check on demand. |
```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { useIsLoggedIn } from "@fast-auth-near/react-sdk";
function Status() {
const { isLoggedIn, isLoading, error, refetch } = useIsLoggedIn();
if (isLoading) return Checking…;
if (error) return ;
return {isLoggedIn ? "Signed in" : "Signed out"};
}
```
On web, `isLoggedIn()` also processes the Auth0 callback parameters when the user is redirected back to your app. Call `refetch` after a redirect completes so the UI reflects the freshly established session.
### `useSigner`
Resolves a relayer-backed `FastAuthSigner` from the client. The signer requires an authenticated user — the client throws `USER_NOT_LOGGED_IN` otherwise, which surfaces as `error`.
```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
function useSigner
| null;
isLoading: boolean;
error: Error | null;
refetch: () => Promise;
};
```
| Param | Type | Default | Description |
| ----------- | --------- | ------- | ------------------------------------------------------------------- |
| `autoFetch` | `boolean` | `true` | Whether to fetch the signer automatically once the client is ready. |
| Return field | Type | Description |
| ------------ | --------------------------- | -------------------------------------------------------------------------- |
| `signer` | `FastAuthSigner
\| null` | The initialized signer, or `null` if not authenticated or not yet fetched. |
| `isLoading` | `boolean` | `true` while the signer is being fetched. |
| `error` | `Error \| null` | The error if fetching failed, otherwise `null`. |
| `refetch` | `() => Promise` | Re-fetches the signer — call this after a login completes. |
```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { useSigner } from "@fast-auth-near/react-sdk";
function SendButton({ transaction }) {
const { signer, isLoading, error } = useSigner();
if (isLoading) return Loading signer…;
if (error) return Error: {error.message};
if (!signer) return Please log in;
return (
);
}
```
### `usePublicKey`
Derives the user's NEAR public key from the signer for the requested algorithm. It composes `useSigner`, so it becomes available as soon as a signer is ready.
```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
function usePublicKey
(
algorithm?: Algorithm,
autoFetch?: boolean,
): {
publicKey: PublicKey | null;
isLoading: boolean;
error: Error | null;
refetch: () => Promise;
};
```
| Param | Type | Default | Description |
| ----------- | -------------------------- | ----------- | -------------------------------------------------------------------- |
| `algorithm` | `"ed25519" \| "secp256k1"` | `"ed25519"` | Which key to derive. Each algorithm yields a distinct public key. |
| `autoFetch` | `boolean` | `true` | Whether to fetch the key automatically once the signer is available. |
| Return field | Type | Description |
| ------------ | --------------------- | ------------------------------------------------------------------- |
| `publicKey` | `PublicKey \| null` | The derived key, or `null` if not authenticated or not yet fetched. |
| `isLoading` | `boolean` | `true` while the key is being derived. |
| `error` | `Error \| null` | The error if derivation failed, otherwise `null`. |
| `refetch` | `() => Promise` | Re-derives the public key on demand. |
```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { usePublicKey } from "@fast-auth-near/react-sdk";
function AccountKey() {
const { publicKey, isLoading, error } = usePublicKey("ed25519");
if (isLoading) return Deriving key…;
if (error) return Error: {error.message};
if (!publicKey) return Please log in;
return {publicKey.toString()};
}
```
Call the hook once per algorithm — the keys are independent, so each identity has both an `ed25519` and a `secp256k1` public key.
```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
function Keys() {
const ed = usePublicKey("ed25519");
const secp = usePublicKey("secp256k1");
return (
{ed.publicKey &&
ed25519: {ed.publicKey.toString()}
}
{secp.publicKey &&
secp256k1: {secp.publicKey.toString()}
}
);
}
```
***
## Client & signer
The hooks hand you a `FastAuthClient` and a `FastAuthSigner`. Both share their surface with the [Browser SDK](/sdks/browser-sdk) classes, but the React variants are pre-wired: the client resolves contract ids from `network`, and the signer is created with relayer support so it can submit transactions on the user's behalf.
### `FastAuthClient`
Access it from `useFastAuth`. It orchestrates login state and produces the signer.
| Method | Signature | Description |
| ------------ | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `login` | `login(...args): void` | Delegates to the auth provider's login. On web this opens the Auth0 popup or redirect; extra args pass straight through to the provider. |
| `logout` | `logout(...args): void` | Ends the session via the provider. |
| `isLoggedIn` | `isLoggedIn(): Promise` | Resolves the current authentication status through the provider. |
| `getSigner` | `getSigner(): Promise>` | Returns an initialized, relayer-backed signer. Throws `FastAuthClientError` with code `USER_NOT_LOGGED_IN` if the user is not authenticated. |
```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { useFastAuth } from "@fast-auth-near/react-sdk";
function LoginFlow() {
const { client } = useFastAuth();
const handleLogin = async () => {
await client?.login();
const loggedIn = await client?.isLoggedIn();
if (loggedIn) {
const signer = await client!.getSigner();
// signer is ready for transactions
}
};
return ;
}
```
### `FastAuthSigner`
Access it from `useSigner`. In the React SDK the signer is relayer-backed, which unlocks two high-level, one-call methods that request the signature, relay it, and submit the result to NEAR for you. Submitting a delegate action requires a relayer to sponsor gas — see NEAR's [meta-transactions guide](https://docs.near.org/protocol/transactions/meta-tx) for how relayers work.
| Method | Signature | Description |
| --------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `signAndSendTransaction` | `signAndSendTransaction(opts): Promise` | Requests a transaction signature from the provider, relays the signature request through a relayer, then signs and submits the transaction. Returns the network's final execution outcome. |
| `signAndSendDelegateAction` | `signAndSendDelegateAction(opts): Promise` | Requests a delegate-action signature and relays it — the relayer pays gas, enabling gasless (meta) transactions. Returns the final execution outcome. |
| `createAccount` | `createAccount(accountId, options?): Promise` | Creates a NEAR account with the user's derived key via the relayer (gas and deposit handled for you). Returns the transaction hash. |
| `getPublicKey` | `getPublicKey(algorithm?): Promise` | Derives the user's public key. Defaults to `"ed25519"`. |
| `getSignatureRequest` | `getSignatureRequest(): Promise` | Retrieves the pending signature request (`guardId`, `verifyPayload`, `signPayload`, optional `algorithm`). |
`signAndSendTransaction` accepts the transaction plus an optional algorithm; its remaining fields are forwarded to the provider's signature request. The MPC algorithm defaults to `"eddsa"`.
```tsx signAndSendTransaction.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { useSigner } from "@fast-auth-near/react-sdk";
function Transfer({ transaction }) {
const { signer } = useSigner();
const send = async () => {
if (!signer) return;
const outcome = await signer.signAndSendTransaction({
transaction,
// algorithm defaults to "eddsa"
});
console.log("Included in block:", outcome.transaction_outcome.block_hash);
};
return ;
}
```
```tsx signAndSendDelegateAction.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { useSigner } from "@fast-auth-near/react-sdk";
// Gasless: the relayer sponsors gas via a delegate action.
function GaslessAction({ receiverId }) {
const { signer } = useSigner();
const send = async () => {
if (!signer) return;
const outcome = await signer.signAndSendDelegateAction({
receiverId,
// algorithm defaults to "eddsa"
});
console.log("Relayed:", outcome);
};
return ;
}
```
```tsx createAccount.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { useSigner } from "@fast-auth-near/react-sdk";
function Onboard({ desiredAccountId }: { desiredAccountId: string }) {
const { signer } = useSigner();
const create = async () => {
if (!signer) return;
const hash = await signer.createAccount(desiredAccountId);
console.log("Created account, tx hash:", hash);
};
return ;
}
```
Prefer `signAndSendDelegateAction` when you want users to transact without holding NEAR — the relayer covers gas. Use `signAndSendTransaction` when the user's account pays its own gas. See [Sign transactions](/home/guides/sign-transactions) for the end-to-end pattern.
***
## Next steps
Wire up login, logout, and session handling with the hooks.
Request signatures and relay transactions, gasless or not.
The framework-agnostic FastAuthClient and FastAuthSigner.
The Auth0 web provider you pass to providerConfig.