@digistra/auth
v3.0.5
Published
Modular auth package for Digistra apps
Downloads
1,753
Maintainers
Readme
@digistra/auth
Runtime auth SDK for Digistra applications.
This package provides route protection, session helpers, server and mock adapters, Next.js middleware integration, and minimal React UI primitives.
Who This Is For
- Frontend developers integrating Digistra auth flows.
- Teams that want predictable route gating in Next.js.
- AI agents that need code-accurate guidance for auth integration.
What This Package Is (And Is Not)
This package is:
- A runtime SDK (
defineDigistraAuth,login,logout,getSession,checkAuth) - Adapter-driven (server adapter, mock adapter, custom adapters)
- Compatible with Next middleware and simple UI primitives
This package is not:
- A full identity provider
- A complete authorization policy engine
- The backend auth service itself
Install
npm install @digistra/authCompatibility
next:>=13.0.0(peer)react:>=18.0.0(peer)react-dom:>=18.0.0(peer)
Exports
@digistra/auth
defineDigistraAuthcreateDigistraAuthServerAdapterDIGISTRA_AUTH_SERVER_BASE_URLlogin,logout,getSession,checkAuth- Core types (
DefineDigistraAuthConfig,DigistraAuthAdapter, etc.)
@digistra/auth/mock
mockAdaptermockAdapterByEnvloadMockUsersseedAuthStoreFromFileseedAuthStoreFromData
@digistra/auth/next
createDigistraMiddleware
@digistra/auth/ui
LoginFormAuthOverlay
Commands
Package Development Commands (this repository)
npm run build
npm run clean
npm pack --dry-runPlatform CLI Commands (npx digistra ...)
There is currently no dedicated @digistra/auth CLI command surface in this package itself.
If your broader Digistra platform exposes auth-related CLI commands, treat those as external tooling (outside this package API contract).
Quick Start
import { defineDigistraAuth, createDigistraAuthServerAdapter, login, checkAuth } from "@digistra/auth";
defineDigistraAuth({
publicRoutes: ["/", "/login", "/public/*"],
privateRoutes: ["/dashboard/*", "/cms/*"],
unauthorizedRedirect: "/login",
adapter: createDigistraAuthServerAdapter({
baseUrl: "https://auth.digistra.dev",
}),
});
const loggedIn = await login({
identifier: "admin",
password: "admin123",
});
const allowed = await checkAuth({
pathname: "/dashboard/settings",
checkOnly: true,
});Configuration
defineDigistraAuth(config)
Registers global auth config as singleton.
Required fields:
publicRoutesprivateRoutesunauthorizedRedirectadapter
Important behavior:
privateRoutesalways win overpublicRoutes- Calling helpers before configuration throws
Core Runtime API
login({ identifier, password })
- Input key is
identifier(notcredential) - Returns
truefor valid credentials,falseotherwise - Headless behavior: no automatic redirect
logout()
- Calls adapter logout when available
- Always clears local session state afterwards
getSession()
- Returns adapter session when adapter provides
getSession - Falls back to local session read otherwise
- Returns
nullwhen unauthenticated
checkAuth({ pathname?, status?, checkOnly? })
Defaults:
checkOnlydefaults totrue
Unauthorized conditions:
status === 401- Private route without valid session/check
Behavior:
checkOnly: true-> returns boolean, no redirectcheckOnly: false-> in browser, redirects tounauthorizedRedirecton unauthorized
Route Matching
Route matching is case-sensitive and supports:
*//*(match all)- Exact paths (example:
/login) - Prefix wildcards (example:
/dashboard/*) - Mixed wildcard patterns (example:
/a/*/b)
Trailing slashes are normalized (/dashboard equals /dashboard/).
Bearer Token Architecture (Production)
In production, @digistra/auth operates on a Zero-Touch Bearer token model. You do not manage tokens manually — the SDK handles storage, injection, and refresh internally.
How it works
Browser ──POST /login──► Server Action (loginWithServer)
│
▼ receives { accessToken, refreshToken }
│
storeServerTokenPair()
│
▼ next/headers cookies.set()
Response ◄── Set-Cookie: ds_at=<jwt>; HttpOnly; Secure; SameSite=Strict
Set-Cookie: ds_rt=<jwt>; HttpOnly; Secure; SameSite=Strict
│
Next Request ──Cookie: ds_at=...──► Edge Middleware (createDigistraMiddleware)
│ reads ds_at → isAuthenticated = true
▼
Server Component / Server Action
readServerTokenPair() → ds_at
fetch(..., { Authorization: "Bearer <at>" })ds_at— Access token.HttpOnly; Secure; SameSite=Strict; MaxAge=15minds_rt— Refresh token.HttpOnly; Secure; SameSite=Strict; MaxAge=7days- Both cookies are HttpOnly (no JS access) and sent automatically in the
Cookieheader on every request, making them readable by the Edge Middleware and Next.js Server functions. - On token expiry the SDK performs an automatic 401-refresh loop: exchanges
ds_rtfor a newds_at, updates the cookie in the current response, and retries the original request — all transparently.
Dev vs Prod toggle
| Environment | Auth check in middleware | Token storage |
|---|---|---|
| development | dsid cookie or digistra_auth_session mock cookie | File-backed mock session |
| production | ds_at HttpOnly cookie | next/headers server cookies |
Internal cookie API
These are exported for use by @digistra/cms and advanced integrations. Normal application code should never call them directly.
import { readServerTokenPair, updateServerAccessToken, DIGISTRA_REFRESH_TOKEN_COOKIE } from "@digistra/auth";readServerTokenPair()— readsds_at+ds_rtfromnext/headerscookiesupdateServerAccessToken(at)— updatesds_atinnext/headerscookies (used after refresh)DIGISTRA_REFRESH_TOKEN_COOKIE— the cookie name"ds_rt"
Server Adapter
createDigistraAuthServerAdapter(options?)
Defaults:
- Base URL:
https://auth.digistra.dev loginPath:/loginlogoutPath:/logoutsessionPath:/sessionrefreshPath:/refresh
Semantics:
login— POSTs credentials, captures{ accessToken, refreshToken }from JSON response, stores inds_at/ds_rtHttpOnly cookies vianext/headers.check/getSession— reads Bearer token from server cookies, retries automatically after 401 with refresh token.logout— revokes refresh token on server, clears bothds_atandds_rtcookies.
Mock Adapters
mockAdapter({ users?, file? })
- Supports inline users and optional JSON file users
- Uses
identifierto match againstuser.credential - Requires stored password for successful auth in mock mode
mockAdapterByEnv(options)
Behavior:
- Defaults to mock mode unless
NODE_ENV === "production" - When
fileoption is provided (Node.js environment):- Reads and writes user data to
{file}/users.json - All reads/writes persist to disk (multi-process safe)
- Perfect for development with Next.js App Router + Turbopack
- Changes visible immediately across tabs/sessions
- Reads and writes user data to
- In non-mock mode:
- Uses
fallbackAdapterwhen provided - Otherwise uses
createDigistraAuthServerAdapter({ baseUrl: authServerBaseUrl })
- Uses
Example with file-backed storage:
import { defineDigistraAuth } from "@digistra/auth";
import { mockAdapterByEnv } from "@digistra/auth/mock";
defineDigistraAuth({
publicRoutes: ["/", "/login"],
privateRoutes: ["/dashboard/*"],
unauthorizedRedirect: "/login",
adapter: mockAdapterByEnv({
file: "node_modules/.digistra/auth",
}),
});This will:
- Create
node_modules/.digistra/auth/users.jsonon first use - Read/write users to this file on every auth operation
- Share user data across processes in development
seedAuthStoreFromFile(seedPath, targetDir) & seedAuthStoreFromData(users, targetDir)
Helper functions to initialize auth store from seed files:
seedAuthStoreFromFile(seedPath, targetDir)- Load users from JSON fileseedAuthStoreFromData(users, targetDir)- Create store from data array- Useful for bootstrapping
.digistra/auth/on app startup or reset
Example:
import { seedAuthStoreFromFile } from "@digistra/auth/mock";
// Initialize auth store from seed
await seedAuthStoreFromFile("./seed-auth.json", "node_modules/.digistra/auth");Seed JSON format:
{
"users": [
{
"id": "user-1",
"name": "Test User",
"credential": "[email protected]",
"password": "password123"
}
]
}loadMockUsers(options)
- Merges inline users + file users
- De-duplicates by
id, fallback keycredential - File loading is server-only (throws in browser)
Next.js Integration
createDigistraMiddleware()
Protects private routes and redirects unauthenticated requests. Runs in the Next.js Edge Runtime — zero server overhead.
// middleware.ts
import { createDigistraMiddleware } from "@digistra/auth/next";
export default createDigistraMiddleware();
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};Behavior by environment:
| | Development | Production |
|---|---|---|
| Auth signal | dsid cookie or digistra_auth_session mock cookie | ds_at cookie (HttpOnly, set by the SDK after login) |
| On failure | Redirect to unauthorizedRedirect | Redirect to unauthorizedRedirect |
- No config loaded → no-op (
NextResponse.next()) - Cookie check is header-only — no network calls in middleware.
UI Components
LoginForm
LoginForm emits { credential, password } in onSubmit.
If you call core login(...), map credential to identifier:
"use client";
import { login } from "@digistra/auth";
import { LoginForm } from "@digistra/auth/ui";
export function LoginPage() {
return <LoginForm onSubmit={({ credential, password }) => login({ identifier: credential, password })} />;
}AuthOverlay
- Resolves session on mount
- Renders
childrenif authorized, otherwisefallback
Session Model
Development cookies
| Cookie | Set by | Purpose |
|---|---|---|
| digistra_auth_session | Mock adapter (browser) | Base64-encoded session JSON |
| dsid | Real auth server | Opaque server session indicator |
Production cookies (internal SDK state)
| Cookie | Set by | Attributes | Purpose |
|---|---|---|---|
| ds_at | loginWithServer via next/headers | HttpOnly; Secure; SameSite=Strict; MaxAge=15min | Access token — read by Edge Middleware and server fetches |
| ds_rt | loginWithServer via next/headers | HttpOnly; Secure; SameSite=Strict; MaxAge=7days | Refresh token — used to obtain a new ds_at on expiry |
Notes:
HttpOnlycookies are never accessible to JavaScript; they are sent automatically in theCookieheader on every browser request.- The Edge Middleware (
createDigistraMiddleware) readsds_atfrom the raw cookie header — no JS ornext/headersrequired at that layer. - After a successful token refresh, the updated
ds_atis written back vianext/headersin the same server response cycle.
Error Handling Pattern
Use explicit boolean checks instead of assuming exceptions for auth failures:
const ok = await login({ identifier, password });
if (!ok) {
// invalid credentials or auth backend unavailable
}For protected fetches:
const response = await fetch("/api/private", { credentials: "include" });
await checkAuth({ status: response.status, checkOnly: false });Development & Testing
Manual Testing with dev-app
A complete Next.js test application is available at ../dev-app/ for manual testing:
cd ../dev-app
npm run reset # Initialize .digistra/auth with seed data
npm run dev # Start dev serverTest scenarios:
- Login page (
/login) - Try test credentials - Multi-session sync - Open login in 2 tabs, verify same users
- Data persistence - Refresh page, data persists
- Reset script - Run
npm run resetto clear and re-seed
Testing workflows documented in: ../dev-app/README.md
File-Based Storage in Development
The file-backed mock adapter enables:
- Real-time sync across multiple tabs/windows
- Persistent storage in
node_modules/.digistra/auth/users.json - Cross-process safety in Next.js Turbopack dev environment
- Easy reset via
npm run resetscript
For AI Agents
When generating code with this package:
- Always initialize once with
defineDigistraAuth(...)before helper usage - Use
identifierin corelogin, notcredential - Treat
falsereturn values as expected auth outcomes (not always exceptional errors) - Keep route examples consistent with private-route precedence
- In UI examples, map
LoginFormcredential field to core login identifier - For development/testing, use
mockAdapterByEnv({ file: "path" })for file-backed persistence
License
MIT
