Skip to content

Server SDKs and Adapters

Seamless Auth currently ships two official server-side packages:

  • @seamless-auth/core
  • @seamless-auth/express

These packages help your backend become the browser-facing security boundary between your app and the private auth server.


PackageUse it whenWhat it gives you
@seamless-auth/expressYour backend is ExpressOfficial adapter, mounted auth routes, middleware, role guards
@seamless-auth/coreYou need a custom adapter or framework integrationFramework-agnostic auth, cookie, OAuth, and role primitives

If you already run Express, start with @seamless-auth/express.


Your backend integration layer is responsible for:

  • receiving browser requests
  • owning signed, HTTP-only auth cookies
  • validating authenticated state
  • enforcing authorization
  • proxying auth flows to the private auth API
  • talking to the auth server with service credentials

That architecture is intentional. Browser cookies should not be forwarded directly to seamless-auth-api as if the auth server were your public application API.


The Express package is the supported batteries-included server integration.

It provides:

  • createSeamlessAuthServer(...)
  • requireAuth({ cookieSecret })
  • requireRole(roleOrRoles)
  • getSeamlessUser(...)
  • createEnsureCookiesMiddleware(...)
  • scoped role helpers re-exported from @seamless-auth/core
import express from 'express'
import cookieParser from 'cookie-parser'
import createSeamlessAuthServer, {
requireAuth,
requireRole,
type SeamlessAuthServerOptions,
} from '@seamless-auth/express'
const app = express()
app.use(express.json())
app.use(cookieParser())
const authOptions: SeamlessAuthServerOptions = {
authServerUrl: process.env.AUTH_SERVER_URL!,
cookieSecret: process.env.COOKIE_SIGNING_KEY!,
serviceSecret: process.env.API_SERVICE_TOKEN!,
issuer: process.env.APP_ORIGIN!,
audience: process.env.AUTH_SERVER_URL!,
jwksKid: process.env.JWKS_KID,
}
app.use('/auth', createSeamlessAuthServer(authOptions))
app.get('/api/me', requireAuth({ cookieSecret: authOptions.cookieSecret }), (req, res) => {
res.json({ user: req.user })
})
app.get(
'/admin/users',
requireAuth({ cookieSecret: authOptions.cookieSecret }),
requireRole('admin:read'),
(_req, res) => {
res.json({ ok: true })
},
)
OptionPurpose
authServerUrlBase URL for the private Seamless Auth API
cookieSecretSecret used to verify and sign adapter cookies
serviceSecretShared service secret matching the auth API API_SERVICE_TOKEN
issuerIssuer/origin value for app-issued cookies
audienceExpected audience, usually the auth server URL

Optional values include jwksKid, cookieDomain, custom cookie names, and messaging.


When mounted at /auth, the Express adapter exposes auth-compatible browser routes such as:

  • /auth/login
  • /auth/oauth/providers
  • /auth/oauth/:providerId/start
  • /auth/oauth/:providerId/callback
  • /auth/webAuthn/login/start
  • /auth/webAuthn/login/finish
  • /auth/webAuthn/register/start
  • /auth/webAuthn/register/finish
  • /auth/otp/*
  • /auth/magic-link*
  • /auth/step-up/*
  • /auth/organizations/*
  • /auth/users/me
  • /auth/users/credentials
  • DELETE /auth/logout
  • DELETE /auth/logout/all
  • /auth/admin/*
  • /auth/internal/*
  • /auth/system-config/*

The adapter route spelling is webAuthn; the raw auth API route group is /webauthn.


requireAuth({ cookieSecret }) verifies the signed access cookie and attaches the decoded payload to req.user.

app.get('/api/profile', requireAuth({ cookieSecret }), (req, res) => {
res.json({ user: req.user })
})

This middleware verifies an already-issued access cookie. Session refresh is handled by the adapter’s cookie middleware.

requireRole(required) performs authorization only. It expects requireAuth to have populated req.user.

app.post(
'/settings',
requireAuth({ cookieSecret }),
requireRole(['admin:write', 'settings:write']),
updateSettings,
)

Scoped role compatibility:

Granted roleSatisfies
adminadmin, admin:read, admin:write
admin:writeadmin:write, admin:read
admin:readadmin:read only

The Express adapter can own email and SMS delivery for auth-message flows.

createSeamlessAuthServer({
authServerUrl,
cookieSecret,
serviceSecret,
issuer,
audience,
messaging: {
email: emailTransport,
sms: smsTransport,
handlers: {
magicLinkEmail: async (message) => {
await deliver(message)
},
},
},
})

When messaging is configured, the adapter requests external-delivery payloads from the auth API, delivers OTPs or one-time links locally, and strips those sensitive payloads before responding to the browser.


The server adapter proxies OAuth and organization routes so your browser app can stay on the same cookie boundary.

OAuth provider configuration belongs on seamless-auth-api, not in the adapter. Configure LOGIN_METHODS to include oauth, add oauth_providers, and store provider client secrets in env vars referenced by clientSecretEnv.

Organization routes let authenticated users create organizations, switch active organization, and manage organization members. Admin organization routes sit under /auth/admin/organizations/*.


The adapter proxies admin hardening endpoints used by the dashboard:

  • DELETE /auth/admin/sessions/by-id/:id
  • DELETE /auth/admin/sessions/:userId/revoke-all
  • POST /auth/admin/users/:userId/recovery/device-replacement

Device replacement recovery requires a fresh step-up session in the auth API. It revokes sessions, removes passkeys, disables TOTP credentials, and returns counts only.


The core package is lower level and framework-agnostic.

It is designed for:

  • custom adapters
  • future framework integrations
  • runtimes where you want full control over request and response handling

Key exports include:

  • ensureCookies(...)
  • refreshAccessToken(...)
  • verifyCookieJwt(...)
  • createServiceToken(...)
  • authFetch(...)
  • getSeamlessUser(...)
  • hasScopedRole(...)
  • login, registration, OTP, magic-link, OAuth, session, and organization handlers

Core functions return descriptive result objects. They do not set Express responses, read environment variables, or own framework-specific behavior.


Today, the strongest supported server-side path is Express.

The best-supported current combination is:

@seamless-auth/react
-> your frontend
@seamless-auth/express
-> your backend integration layer
seamless-auth-api
-> your auth engine

Use @seamless-auth/core when Express is not your runtime or you are building an adapter.