@veroai/auth
v0.7.0
Published
VeroAI Auth SDK - Authentication, user management, and Hono middleware
Maintainers
Readme
@veroai/auth
Authentication SDK for VeroAI — auth-as-a-service for apps built on the Vero platform. Email/password, MFA (TOTP), OAuth2/OIDC SSO, automatic token refresh.
npm install @veroai/authPick a model
@veroai/auth ships three auth models. They are independent — an app
picks one. Use the table, then jump to that section.
| | BFF · credentials | BFF · OAuth SSO | Pure SPA OAuth |
|---|---|---|---|
| Entry | mountCredentialAuth | mountAuthRoutes | VeroAuthSpa |
| Your app has a server (Worker / Node) | required | required | not needed |
| Login UI | your own form | Vero hosted login | your own form¹ |
| Tokens live in | httpOnly cookie (server) | httpOnly cookie (server) | browser memory |
| Browser holds a token | no | no | yes (bearer) |
| Talks to Vero APIs via | your server proxies | your server proxies | direct bearer header |
| Secret needed | a Vero API key | OAuth client id+secret | none (public client) |
| Enterprise SSO / SAML | no | yes | no |
| Best for | apps with a backend that want their own login screen | apps that want Vero/SAML hosted login | static SPAs with no backend |
¹ The SPA form collects the email; the actual credential check still happens on authsrv via the OAuth redirect.
Rule of thumb: has a backend → BFF (credentials, or OAuth for SSO). No backend, SPA talks straight to APIs → pure SPA OAuth.
Model 1 — BFF, direct credentials (mountCredentialAuth)
The Auth0/Clerk pattern. Your app ships its own email/password form. Credentials POST to your server, which holds a Vero API key and authenticates against Vero. The session lives in an AES-GCM-sealed httpOnly cookie — the browser never holds a token. No redirect.
Server (Hono — Cloudflare Worker / Node)
import { Hono } from 'hono';
import { mountCredentialAuth } from '@veroai/auth/server';
const app = new Hono();
mountCredentialAuth(app, {
veroApiKey: env.VERO_API_KEY, // sk_live_… — account-scoped
cookie: { encryptionKey: env.SESSION_ENCRYPTION_KEY }, // openssl rand -base64 32
signupTenantId: env.TENANT_ID, // optional — enables POST /auth/signup
});Mounts (default basePath /auth):
| Route | Purpose |
|---|---|
| POST /auth/login | {email,password} → session cookie, or {mfa_required,mfa_token} |
| POST /auth/signup | register + sign in (only if signupTenantId set) |
| POST /auth/mfa | {mfa_token,code} → session cookie |
| POST /auth/refresh | rotate the session |
| POST /auth/logout | revoke + clear cookie |
| GET /auth/me | identity envelope |
| GET/POST /auth/mfa/{status,setup,verify-setup,disable} | MFA management |
Config takes just two secrets: veroApiKey + cookie.encryptionKey.
Browser / React
import { AuthProvider, useAuth } from '@veroai/auth/react';
<AuthProvider config={{ apiUrl: '', basePath: '/auth' }}>
<App />
</AuthProvider>;
function LoginForm() {
const { signIn, signUp, completeMfa, user, isLoading } = useAuth();
async function onSubmit(email: string, password: string) {
const r = await signIn(email, password);
if (r.mfa_required) {
// collect a 6-digit code, then:
await completeMfa(r.mfa_token, code);
}
// on success the provider re-hydrates `user`
}
}AuthProvider runs a silent-renew timer while signed in (autoRefresh,
default on). useAuth().fetch() is a fetch wrapper that retries once on
401 after refreshing.
Model 2 — BFF, OAuth hosted login (mountAuthRoutes)
The same BFF cookie model, but login is the OAuth2 Authorization Code + PKCE flow against Vero's hosted login page. Use this for enterprise SSO — SAML still requires browser redirects.
import { mountAuthRoutes } from '@veroai/auth/server';
mountAuthRoutes(app, {
authsrv: { url: 'https://auth.veroagents.com' },
oauthClient: { id: env.OAUTH_CLIENT_ID, secret: env.OAUTH_CLIENT_SECRET, audience: 'vero-core' },
cookie: { encryptionKey: env.SESSION_ENCRYPTION_KEY },
redirects: { appOrigin: 'https://app.example.com' },
});Browser: useAuth().login() redirects to the hosted login; the rest of
useAuth() (logout, me, fetch, refresh) is shared with Model 1.
Model 3 — pure SPA OAuth (VeroAuthSpa)
The @auth0/auth0-spa-js pattern. No server, no cookie, no API key. The SPA
runs Authorization Code + PKCE directly against authsrv as a public
client, holds tokens in memory, and sends the access token to APIs as a
Authorization: Bearer header. Renewal is refresh-token rotation.
import { SpaAuthProvider, useSpaAuth } from '@veroai/auth/spa-react';
<SpaAuthProvider
config={{
domain: 'https://auth.veroagents.com',
clientId: 'your-public-client-id',
redirectUri: window.location.origin + '/callback',
audience: 'vero-core',
}}
>
<App />
</SpaAuthProvider>;
function Page() {
const { isAuthenticated, user, loginWithRedirect, logout, getAccessToken } = useSpaAuth();
if (!isAuthenticated) return <button onClick={() => loginWithRedirect()}>Log in</button>;
async function callApi() {
const token = await getAccessToken(); // refreshes if stale
await fetch('https://api.example.com/x', {
headers: { Authorization: `Bearer ${token}` },
});
}
}On the /callback route the provider completes the code exchange
automatically. Tokens are in memory only — a full page reload signs the user
out client-side; call loginWithRedirect() again (authsrv's session cookie
makes that a no-prompt bounce).
Without a React app, use VeroAuthSpa from @veroai/auth/spa directly:
loginWithRedirect(), handleRedirectCallback(), getAccessToken(),
getUser(), logout().
Requires a public OAuth client registered with authsrv
(client_type=public, your redirect URI, audience allowlisted) and the
SPA origin added to authsrv's CORS allow-list.
API token verification (@veroai/auth/hono)
Verify Vero-issued access tokens on your own API routes — local ES256 verification against authsrv's JWKS, no per-request call.
import { veroAuth, getVeroUser } from '@veroai/auth/hono';
app.use('/v1/*', veroAuth({
authsrvUrl: 'https://auth.veroagents.com',
audience: 'vero-core',
}));
app.get('/v1/thing', (c) => c.json({ user: getVeroUser(c) }));Accepts a Authorization: Bearer header (SPA / service callers) or the
vero_session BFF cookie — so it works downstream of any of the three
models.
Federation end-user tokens
veroAuth also verifies the Vero customer-federation end-user JWTs
minted via @veroai/sdk's federation.endUserToken / federation.federate
(see FEDERATED.md).
They're authsrv-signed ES256 like any other Vero JWT; the audience is
typically msgsrv, agentsrv, or voicesrv.
import {
veroAuth,
getVeroUser,
isFederationToken,
getExternalId,
getSessionId,
} from '@veroai/auth/hono';
app.use(veroAuth({
authsrvUrl: 'https://auth.veroagents.com',
audience: 'msgsrv', // or 'agentsrv'
}));
app.post('/chat/send', (c) => {
const user = getVeroUser(c);
if (isFederationToken(user)) {
// request comes from a customer's federated end-user
const externalId = getExternalId(c); // customer's opaque user id
const sessionId = getSessionId(c); // revocation pivot
// …propagate externalId into your audit log / webhook payload…
}
// …handler body…
});VeroJwtPayload carries optional external_id and session_id fields;
they're present only on federation tokens. roles includes the
federation scope claim (array or space-string forms both supported).
For live revocation checks against revoked:sessions:{session_id} see
the consumer pattern in
msgsrv
or agentsrv.
Subpath exports
| Import | Use |
|---|---|
| @veroai/auth | shared types, VeroAuth server client, errors |
| @veroai/auth/server | mountCredentialAuth, mountAuthRoutes (Hono) |
| @veroai/auth/browser | VeroAuthBrowser — BFF browser client |
| @veroai/auth/react | AuthProvider, useAuth — BFF React bindings |
| @veroai/auth/spa | VeroAuthSpa — pure SPA OAuth client |
| @veroai/auth/spa-react | SpaAuthProvider, useSpaAuth |
| @veroai/auth/hono | veroAuth token-verification middleware |
Token lifetimes
Access token 15 min, refresh token 30 days (rotating). All three models refresh automatically — you never handle a refresh token by hand.
License
MIT
