Adding Auth to Your App
Zyphr Auth-as-a-Service lets you add complete user authentication to any application without building it yourself. Your app talks to the Zyphr API, which handles registration, login, sessions, MFA, OAuth, and more for your end users.
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Your App │──────▶│ Zyphr API │──────▶│ End Users │
│ (Frontend/ │◀──────│ │◀──────│ │
│ Backend) │ └─────────────┘ └─────────────┘
└─────────────┘
Two Authentication Models
Zyphr supports two credential models depending on where your auth calls originate:
| Model | Headers | Use Case |
|---|---|---|
| Server-side | X-Application-Key + X-Application-Secret | Backend API calls (registration, login, token management) |
| Client-side | X-Application-Key only + Authorization: Bearer <token> | Frontend calls with a user's access token (profile, sessions) |
Never expose your secret key in client-side code. Use the public key + user token model for frontend calls.
Step 1: Create an Application
Applications are containers for your end users. Each application gets its own keys, user pool, and configuration. You can create applications through the Dashboard or the API.
Via Dashboard
- Navigate to Applications in the sidebar
- Click Create Application
- Enter your application name and configure settings
- Copy the secret key — it is only shown once
- Store credentials in your environment variables
Via API
curl -X POST https://api.zyphr.dev/v1/applications \
-H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
-H "Content-Type: application/json" \
-d '{
"name": "My SaaS App",
"session_duration_value": 60,
"session_duration_unit": "minutes",
"refresh_token_duration_days": 30,
"allowed_origins": ["https://myapp.com"],
"redirect_uris": ["https://myapp.com/auth/callback"]
}'
The response includes your keys — save them immediately, the secret key is only shown once:
{
"data": {
"id": "app_abc123",
"name": "My SaaS App",
"public_key": "za_pub_xxxx",
"secret_key": "za_sec_xxxx",
"environments": [
{ "mode": "live", "public_key": "za_pub_live_xxxx", "secret_key": "za_sec_live_xxxx" },
{ "mode": "test", "public_key": "za_pub_test_xxxx", "secret_key": "za_sec_test_xxxx" }
]
},
"meta": {
"warning": "Save all secret keys securely. They will not be shown again."
}
}
See Applications for full CRUD documentation.
Step 2: Configure Your Backend
Store your application credentials as environment variables:
ZYPHR_API_KEY=zy_live_xxxx # Your Zyphr API key
ZYPHR_APP_PUBLIC_KEY=za_pub_xxxx # Application public key
ZYPHR_APP_SECRET_KEY=za_sec_xxxx # Application secret key
Using the Node.js SDK
import { Zyphr } from '@zyphr-dev/node-sdk';
const zyphr = new Zyphr({
apiKey: process.env.ZYPHR_API_KEY!,
applicationKey: process.env.ZYPHR_APP_PUBLIC_KEY!,
applicationSecret: process.env.ZYPHR_APP_SECRET_KEY!,
});
Using Raw HTTP
All server-side auth requests require both application headers:
const ZYPHR_BASE = 'https://api.zyphr.dev/v1';
async function zyphrAuth(path, body) {
const response = await fetch(`${ZYPHR_BASE}${path}`, {
method: 'POST',
headers: {
'X-Application-Key': process.env.ZYPHR_APP_PUBLIC_KEY,
'X-Application-Secret': process.env.ZYPHR_APP_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
return response.json();
}
Step 3: Register Users
POST /v1/auth/register creates a Zyphr platform account (for the dashboard). To register end users in your application, use POST /v1/auth/users/register. If your response includes account, project, or a JWT with aud: "zyphr:dashboard", you're hitting the wrong endpoint.
Using the SDK
const result = await zyphr.auth.registration.registerEndUser({
registerRequest: {
email: 'jane@example.com',
password: 'SecureP@ss123',
name: 'Jane Doe',
metadata: { plan: 'pro' },
},
});
// result.data.user — the new end user
// result.data.tokens — { access_token, refresh_token, expires_in, token_type }
Using cURL
curl -X POST https://api.zyphr.dev/v1/auth/users/register \
-H "X-Application-Key: za_pub_xxxx" \
-H "X-Application-Secret: za_sec_xxxx" \
-H "Content-Type: application/json" \
-d '{
"email": "jane@example.com",
"password": "SecureP@ss123",
"name": "Jane Doe",
"metadata": { "plan": "pro" }
}'
const result = await zyphrAuth('/auth/users/register', {
email: 'jane@example.com',
password: 'SecureP@ss123',
name: 'Jane Doe',
metadata: { plan: 'pro' },
});
// result.data.user — the new user object
// result.data.tokens — { access_token, refresh_token, expires_in, token_type }
Registration returns tokens immediately so the user is logged in after signup.
See End User Authentication for password requirements, validation, and error handling.
Step 4: Login Users
curl -X POST https://api.zyphr.dev/v1/auth/users/login \
-H "X-Application-Key: za_pub_xxxx" \
-H "X-Application-Secret: za_sec_xxxx" \
-H "Content-Type: application/json" \
-d '{
"email": "jane@example.com",
"password": "SecureP@ss123"
}'
const result = await zyphrAuth('/auth/users/login', {
email: 'jane@example.com',
password: 'SecureP@ss123',
});
if (result.data.mfa_required) {
// User has MFA enabled — prompt for TOTP code
// See Step 6 and the MFA docs
const { token, expires_at } = result.data.mfa_challenge;
} else {
// Standard login — store tokens
const { access_token, refresh_token } = result.data.tokens;
}
Login supports optional custom_claims to embed application-specific data in the JWT (max 4KB):
{
"email": "jane@example.com",
"password": "SecureP@ss123",
"custom_claims": { "role": "admin", "org_id": "org_123" }
}
Claims supplied on login are per-issuance — you must pass them on every login,
and they are not remembered between sessions. If you use claims for authorization
decisions (e.g. an admin flag), set them once via the secret-key
PUT /v1/auth/users/{user_id}/claims endpoint instead. Stored claims are
server-set only (clients can't write them, which is what makes them safe for
authz), are embedded automatically into the user's tokens on every login and
refresh, and support seamless demotion: updating a user's claims takes effect
on their next token refresh without forcing a logout. For an immediate hard
cut-off, call POST /v1/auth/sessions/revoke-all. Apps that treat claims as an
authorization gate can also set revocation_fail_closed on the application so the
revocation check fails closed if the store is briefly unreachable.
See End User Authentication for the complete login flow including error handling.
Step 5: Token Management
Access tokens are short-lived JWTs. Use the refresh token to get new ones:
curl -X POST https://api.zyphr.dev/v1/auth/sessions/refresh \
-H "X-Application-Key: za_pub_xxxx" \
-H "X-Application-Secret: za_sec_xxxx" \
-H "Content-Type: application/json" \
-d '{ "refresh_token": "zrt_xxxx" }'
const result = await zyphrAuth('/auth/sessions/refresh', {
refresh_token: storedRefreshToken,
});
const { access_token, refresh_token } = result.data.tokens;
// Store new tokens — old refresh token is now invalid
To log out, revoke the session:
curl -X POST https://api.zyphr.dev/v1/auth/sessions/revoke \
-H "X-Application-Key: za_pub_xxxx" \
-H "X-Application-Secret: za_sec_xxxx" \
-H "Content-Type: application/json" \
-d '{ "refresh_token": "zrt_xxxx" }'
See End User Authentication for session management, revoke-all, and active session listing.
Step 6: Add Enhancements
Once basic auth is working, you can layer on additional features:
| Feature | Description | Guide |
|---|---|---|
| Magic Links | Passwordless email login | Magic Links |
| OAuth / Social Login | Google, Apple, GitHub, etc. | OAuth |
| Multi-Factor Auth | TOTP-based 2FA with backup codes | MFA |
| Password Policies | Configurable requirements per app | Security |
| Email Verification | Verify user email addresses | Security |
| Phone Auth | SMS OTP registration and login | Security |
| WebAuthn / Passkeys | Biometric / hardware key auth | Security |
| Account Lockouts | Brute-force protection | Security |
| User Impersonation | Admin debug access (audited) | Security |
Reacting to auth events (webhooks)
Zyphr emits webhooks for the full end-user lifecycle — all under the user.*
namespace (user.created, user.login, user.password_changed,
user.email_verified, user.mfa_enabled, user.deleted, and more). See the
Auth Events table for
the complete list of 12 event types.
Next Steps
- End-User Field & Endpoint Matrix — Every stored attribute, which endpoint returns it, and at which scope
- Applications — Manage apps, keys, and environments
- End User Authentication — Full registration, login, session, and profile API
- Verifying tokens & JWKS — Per-algorithm claim sets and offline verification
- Security Features — Password policies, lockouts, impersonation, and more