Authaz logoAuthaz
DocumentationAPI Reference
  • Get Started

    • Authaz
    • Core Concepts
    • Set up your app
    • Quickstart — cURL
  • Authentication

    • Authentication Settings
    • Signup
    • Invitations
    • Password Authentication
    • Multi-Factor Auth
    • Magic Link
    • OAuth / Social Login
    • Passkey (WebAuthn)
    • SAML SSO
    • Machine-to-Machine (M2M)
    • API Keys
  • Authorization

    • Authorization
    • Resources
    • Policies
    • Roles
    • Access Explorer
  • Tenancy

    • Multi-tenancy
    • Tenancy Customization
  • Brand & Host

    • Branding
    • Custom Domains
    • Communications & Email Templates
  • Operate

    • Users
    • Analytics
    • Audit Logs
    • Application Settings
  • SDK Quickstarts

    • Quickstart — Next.js
    • Quickstart — React SPA
    • Quickstart — Hono
    • Quickstart — .NET (Authaz.Sdk)
  • Recipes

    • Recipes & Cookbook
    • Next.js — first integration
    • Next.js — B2B SaaS (multi-tenant)
    • Hono — first integration
    • Hono — B2B SaaS (multi-tenant)
    • React SPA — first integration
    • React SPA — B2B SaaS (multi-tenant)
    • .NET — first integration
    • .NET — B2B SaaS (multi-tenant)
  • Reference

    • Tokens
    • API Reference
    • Errors & Troubleshooting
  • Documentation

    • How Authaz is Built
  1. Authaz
  2. Docs
  3. Authentication
  4. API Keys

Authentication

API Keys

3 min read·Updated Jun 19, 2026

API Keys let your customers create credentials they can use to call your API — long-lived tokens with a recognizable prefix (e.g. sk_live_xxxxxxxxxxxx) that they paste into integrations, scripts, and CI. Authaz handles the issuance, hashing, scoping, and validation for you.

This is different from M2M. M2M is for your internal services (one credential per service). API Keys are for end users and customer integrations (potentially thousands of keys per application).

# Enable the API key provider
curl -X PUT https://your-app.authaz.io/api/v1/applications/{appId}/auth/api-keys \
  -H "X-API-Key: $AUTHAZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "keyPrefix": "sk_live_",
    "maxKeysPerUser": 10,
    "requireExpiration": true,
    "defaultExpirationDays": 365
  }'

Two flavors#

User-bound keys

Previous
Machine-to-Machine (M2M)
Next
Authorization
#

A key tied to a specific user. The key inherits whatever the user can do — same roles, same tenant, same permissions. Revoking the user revokes all of their keys. This is the right default for most products.

# Issued by the user from your dashboard, on their own behalf
curl -X POST https://your-app.authaz.io/api/v1/users/me/api-keys \
  -H "Authorization: Bearer USER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "GitHub Actions deploy",
    "expiresAt": "2027-01-01T00:00:00Z"
  }'
{
  "id": "key_01h...",
  "key": "sk_live_xxxxxxxxxxxx",
  "name": "GitHub Actions deploy",
  "createdBy": "user_01h...",
  "expiresAt": "2027-01-01T00:00:00Z"
}

The key is shown once. After this response, only the prefix and last few characters are stored — irreversible bcrypt hash for the rest.

Standalone keys#

Not tied to a user. You assign roles directly to the key. Use these for org-wide automations where there's no specific person who owns the action.

curl -X POST https://your-app.authaz.io/api/v1/applications/{appId}/api-keys \
  -H "X-API-Key: $AUTHAZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Webhook integration",
    "roleIds": ["role_webhook_publisher"],
    "expiresAt": "2027-01-01T00:00:00Z"
  }'

Configuration#

SettingWhat it controls
keyPrefixVisible identifier — e.g. sk_live_, pk_test_, acme_. Visible in audit logs and lets users spot leaked keys at a glance.
maxKeysPerUserCap on user-bound keys. Defaults to unlimited.
maxStandaloneKeysCap on standalone keys for the application.
requireExpirationWhen true, every key must have an expiresAt. Recommended.
defaultExpirationDaysIf requireExpiration is true and the user doesn't specify, this is used.
allowedScopesOptional whitelist. If set, keys can only be issued with these scopes.

Validating a key server-side#

Your backend receives sk_live_xxxxxxxxxxxx in an Authorization: Bearer … or X-API-Key: header from the customer. Verify it before trusting it:

curl -X POST https://your-app.authaz.io/api/v1/api-keys/introspect \
  -H "X-API-Key: $AUTHAZ_MANAGEMENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "key": "sk_live_xxxxxxxxxxxx" }'
{
  "active": true,
  "id": "key_01h...",
  "name": "GitHub Actions deploy",
  "userId": "user_01h...",
  "tenantId": "tenant_01h...",
  "scopes": ["invoices:read"],
  "expiresAt": "2027-01-01T00:00:00Z"
}

If the key was revoked, expired, or never existed, you get { "active": false }. Cache positive results for 30–60 seconds to avoid hammering Authaz on hot paths — but invalidate on any 4xx from your downstream calls.

Letting users manage their own keys#

Most products surface API keys in a settings page. The endpoints are designed to be called with the user's own access token (Bearer):

GET    /api/v1/users/me/api-keys              # list mine
POST   /api/v1/users/me/api-keys              # create one
DELETE /api/v1/users/me/api-keys/{keyId}      # revoke one

Users can only see and revoke their own keys. The Management API key (X-API-Key) sees everything in the application.

Tenant-scoped keys#

In multi-tenant applications, keys live inside a tenant by default — they can only access resources within that tenant, even if the issuing user belongs to several:

curl -X POST https://your-app.authaz.io/api/v1/applications/{appId}/tenants/{tenantId}/api-keys \
  -H "X-API-Key: $AUTHAZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Corp deploy bot",
    "roleIds": ["role_deployer"]
  }'

The introspection response includes tenantId; your backend uses that to scope downstream queries.

Rotating and revoking#

# Rotate — new value returned, old value invalid immediately
curl -X POST https://your-app.authaz.io/api/v1/api-keys/{keyId}/rotate \
  -H "X-API-Key: $AUTHAZ_API_KEY"
 
# Revoke
curl -X DELETE https://your-app.authaz.io/api/v1/api-keys/{keyId} \
  -H "X-API-Key: $AUTHAZ_API_KEY"

For incidents, you can also revoke every key created by a specific user in one call — useful if their employee laptop walked off:

curl -X POST https://your-app.authaz.io/api/v1/users/{userId}/api-keys/revoke-all \
  -H "X-API-Key: $AUTHAZ_API_KEY"

Storage and security#

Authaz never stores plaintext keys. The flow:

  1. Generate 32 bytes of cryptographic randomness, base32-encode, prefix with keyPrefix.
  2. Show the user the full key one time.
  3. Hash the key with bcrypt (cost 12) and store the hash + the visible prefix.
  4. On every request, look up by prefix → bcrypt-compare against the candidate.

This means even a full database compromise doesn't leak active keys. The prefix is enough for support and abuse triage but not enough to authenticate.

Next steps#

  • M2M — for your internal service-to-service calls.
  • API Reference — the Management API authenticates via API keys (and so do your customer integrations).
  • Multi-tenancy — keys can be tenant-scoped automatically.