Skip to main content
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 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. For the guard registry it routes into, see JWT Guard Router.

What it does

Routes by guard_id

Extracts the prefix from guard_id and dispatches to the matching guard contract — jwt routes to the JWT Guard Router.

Verifies before signing

Delegates JWT verification to the guard. No signature is ever produced unless the guard approves the request.

Coordinates MPC

On success, forwards a signing request to the MPC contract at the deterministic path {guard_id}#{sub}.

Refunds on failure

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.
MethodAccessDescription
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 onlyRegister a guard contract under guard_id. The id must not contain #.
remove_guard(guard_id)Owner onlyRemove a guard from the registry.
get_guard(guard_id)Public viewReturn the account id registered for guard_id. Panics if it does not exist.
set_mpc_address(mpc_address)Owner onlySet the MPC contract account the signing requests are sent to.
set_mpc_key_version(mpc_key_version)Owner onlySet the MPC key version (u32, default 0) used by the legacy secp256k1 request.
set_mpc_domain_id(mpc_domain_id)Owner onlySet the MPC domain id (u64, default 1) used by ecdsa / eddsa requests.
pause()Pauser onlyHalt the contract. Most methods panic while paused.
unpause()Owner onlyResume the contract after a pause.
change_owner(new_owner)Owner onlyTransfer administrative ownership.
set_pauser(pauser)Owner onlySet the account allowed to call pause().
paused() / owner() / mpc_address() / mpc_key_version() / mpc_domain_id() / version()Public viewRead 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_idPrefix used for routingMeaning
jwtjwtRoutes to the guard registered as jwt (the JWT Guard Router).
jwt#auth0jwtRoutes 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, which forwards to the correct downstream guard.
// 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:
AlgorithmCurve / schemeMPC request
secp256k1ECDSA on secp256k1 (legacy)SignRequest, uses mpc_key_version
ecdsaECDSA with domain supportSignRequestV2, uses mpc_domain_id
eddsaEdDSA (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:
1

Verification fails or is rejected

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.
2

MPC signing fails

If verification passed but the MPC contract returns an error, the callback refunds the original deposit to the caller and returns None.
3

Success

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.

JWT Guard Router

The registry the jwt prefix routes into, and how it dispatches to the Auth0 guard.

MPC signing

How distributed key shares produce a signature at a deterministic derivation path.

Contracts overview

How the entry point, router, and guards fit together.

Deployed addresses

Mainnet account ids for the contract, router, guards, and MPC.