Sign-In, Users, and Permissions API

Secure Sign-In and User Managementfor Your Website, App, or AI

Your customers can use passwords, passkeys, email codes, or a provider to sign in. AuthJet stores their records beside your app's data and enforces route permissions before your code runs. One sign-in covers every app you register on Substrio.

Route Gates

Caller
  1. GET /products public 200 Handler runs 200 Handler runs 200 Handler runs 200 Handler runs 200 Handler runs
  2. GET /orders/mine auth 401 CREDENTIAL_REQUIRED 200 Handler runs 200 Handler runs 200 Handler runs 200 Handler runs
  3. POST /orders verified 401 CREDENTIAL_REQUIRED 200 Handler runs 200 Handler runs 200 Handler runs 200 Handler runs
  4. GET /reports auth:ADMIN 401 CREDENTIAL_REQUIRED 403 PERMISSION_DENIED 200 Handler runs 200 Handler runs 403 PERMISSION_DENIED
  5. GET /contact-requests owner 401 CREDENTIAL_REQUIRED 403 PERMISSION_DENIED 403 PERMISSION_DENIED 200 Handler runs 403 PERMISSION_DENIED

Decided by the platform before your code runs.

Sign-in providers built in

  • Google
  • Apple
  • GitHub
  • Microsoft
  • Discord
  • X
  • Meta
  • OpenID Connect

The Platform

Sign-In, Users, and Permissionsin One System

You no longer have to keep a separate sign-in database in sync with your app. Your users are records in the database your app already uses.

Sign-In for Every Device

Let people use a password, passkey, or email code. You can also offer Google, Apple, GitHub, Microsoft, Discord, X, Meta, or an OpenID Connect provider.

Multi-Factor Authentication

Require a second factor for every account member with one setting. Each member can use an authenticator app and gets ten recovery codes that work once.

User Records Beside Your App Data

Add the fields and indexes your app needs directly to its user records. You can add a customer before they sign in and use the same record after their first login.

Permissions and Organizations

Grant up to 64 named permissions for a team, store, or customer account. Declare the required permission next to the route. Revocation takes effect on the next request.

One Sign-In

One Account for Every AppYou Run on Substrio

Your store, admin dashboard, and partner portal can use the same sign-in through OpenID Connect. People sign in at your identity app once. Signing out there ends access across the connected apps.

Identity App OpenID Connect · PKCE Store Admin Mobile API Partner Portal
Sign in once Sign out everywhere Example apps
Sign-in providers
13
Named permissions per app
64
Route gate words
6
One-time recovery codes
10

Get Started

Add AuthJet to Your Productin Three Steps

Configure your sign-in methods and declare which routes require a signed-in user or a named permission. Substrio enforces those rules before your handler runs.

  1. 1Create a Substrio Account

    Use the same Substrio account for every Jet. You can use AuthJet separately or with the other apps.

  2. 2Declare Sign-In and Permissions

    Configure your providers and roles in substrio.toml alongside the permission catalog. Apply the configuration with a deploy.

  3. 3Gate Your Routes

    Add a gate word next to each route in routes.json. Requests without the required credentials or permissions are refused before your handler runs.

The API

Sign-In Responsesand Permission Errors

A missing second factor returns a challenge. A denied permission returns 403 and names the required permission.

Sign In

POST /v1/_auth/login 200
{
  "success": true,
  "user_id": 1,
  "token": "p4sH7M...",
  "keyring": "0xffffffffffffffff"
}

Who Is Signed In

GET /v1/_auth/me 200
{
  "user_id": 1,
  "email": "[email protected]",
  "keyring": "0xffffffffffffffff",
  "email_verified": false,
  "mfa_enabled": false,
  "locked": false,
  "disabled": false,
  "admin": false,
  "superadmin": false,
  "source": "native",
  "created_at": 1791374435,
  "last_login": 1791374435
}

Second Factor Required

POST /v1/_auth/login 401
{
  "error": "mfa_required",
  "challenge": "substrio_mfa_...",
  "expires_at": 1791374735,
  "attempts_left": 5
}

Route Refused

GET /reports (auth:ADMIN) 403
{
  "error": "Permission denied",
  "code": "PERMISSION_DENIED",
  "status": 403,
  "retryable": false,
  "next_action": "request_permission",
  "detail": "This route requires the permission \"ADMIN\""
}

Permission Catalog

GET /v1/_permissions 200
{
  "names": [
    {
      "name": "READ",
      "bit": 0,
      "implies": []
    },
    {
      "name": "WRITE",
      "bit": 1,
      "implies": ["READ"]
    },
    {
      "name": "ADMIN",
      "bit": 2,
      "implies": ["READ", "WRITE"]
    }
  ],
  "all": "ADMIN"
}

Security

Sign-Out Takes Effecton the Next Request

Sessions are stored on the server and can be revoked immediately. New passwords are hashed with Argon2id, and authenticator secrets are encrypted with AES-256-GCM.

Instant Sign-Out

Sessions are stored on the server. When your user signs out, the session is refused on its next request in every app they signed in to.

Argon2id Passwords

New passwords are hashed with Argon2id. Imported bcrypt, PBKDF2, and Argon2id hashes continue to work.

Sealed Secrets

Authenticator secrets are encrypted with AES-256-GCM. Recovery codes are stored only as SHA-256 digests.

No Account Probing

A password reset returns the same response for an address with an account and an address without one.

Attempt Limits

After five wrong codes, a sign-in challenge cannot be used again. Five consecutive failures block recovery and MFA changes for 15 minutes.

Tamper-Evident Audit Trail

Changes to keys, settings, and rules are recorded in a chain of digests. You can verify the chain end to end.

All security details