Type-safe, plugin-first authentication core for TypeScript applications.
- Plugin architecture for auth methods and domain capabilities.
- Strongly typed register/authenticate payloads inferred from enabled plugins.
- Path-based issue model (
{ message, path }) for field-level error mapping. - Built-in methods: password, email OTP, magic link, OAuth2, passkey.
- Built-in domain plugins: two-factor auth (TOTP/recovery code), organizations/RBAC.
- Framework-agnostic core for TypeScript apps running in Node-compatible server environments.
npm install @oglofus/authpnpm add @oglofus/authbun add @oglofus/authvp install @oglofus/authOptional for app-level integrations:
arcticfor OAuth providers in your app code.@oslojs/otpif you need direct OTP utilities in your app (the library already uses it internally for TOTP).stripeif you use the Stripe billing plugin.
import{OglofusAuth,passwordPlugin,typePasswordCredentialAdapter,typeSessionAdapter,typeUserAdapter,typeUserBase,}from"@oglofus/auth";interfaceAppUserextendsUserBase{given_name: string;family_name: string;}constusers: UserAdapter<AppUser>=/* your adapter */;constsessions: SessionAdapter=/* your adapter */;constcredentials: PasswordCredentialAdapter=/* your adapter */;constauth=newOglofusAuth({adapters: { users, sessions },plugins: [passwordPlugin<AppUser,"given_name"|"family_name">({requiredProfileFields: ["given_name","family_name"]asconst,
credentials,}),]asconst,validateConfigOnStart: true,});constregistered=awaitauth.register({method: "password",email: "nikos@example.com",password: "super-secret",given_name: "Nikos",family_name: "Gram",});constloggedIn=awaitauth.authenticate({method: "password",email: "nikos@example.com",password: "super-secret",});OglofusAuth exposes:
discover(input, request?)register(input, request?)authenticate(input, request?)method(pluginMethod)for plugin-specific APIsverifySecondFactor(input, request?)completeProfile(input, request?)validateSession(sessionId, request?)signOut(sessionId, request?)
Organization session switching is exposed by the organizations plugin API:
constorgApi=auth.method("organizations");awaitorgApi.setActiveOrganization({sessionId: "session_123",organizationId: "org_123",});awaitorgApi.setActiveOrganization({sessionId: "session_123"});// clearAll operations return structured results.
if(!result.ok){console.log(result.error.code);// e.g. "INVALID_INPUT"console.log(result.error.status);// HTTP-friendly status codeconsole.log(result.issues);// path-based issues}Issue format:
typeIssue={message: string;path?: ReadonlyArray<PropertyKey|{key: PropertyKey}|{index: number}>;};You can build issues with helpers:
import{createIssue,createIssueFactory}from"@oglofus/auth";constissue=createIssueFactory<{email: string;profile: unknown}>(["email","profile"]asconst);issue.email("Email is required");issue.$path(["profile",{key: "addresses"},{index: 0},"city"],"City is required");createIssue("Generic failure");- Method:
"password" - Register + authenticate supported.
- Config:
requiredProfileFields,credentialsadapter.
- Method:
"email_otp" - Two-step flow with plugin API:
auth.method("email_otp").request({ email })auth.authenticate(...)orauth.register(...)withchallengeId+code
- Method:
"magic_link" - Two-step flow with plugin API:
auth.method("magic_link").request({ email })auth.authenticate(...)orauth.register(...)withtoken
- Method:
"oauth2" - Uses provider exchange callbacks. Arctic clients can be wrapped with
arcticAuthorizationCodeExchange(...). - Supports profile completion when required fields are missing.
import{Google}from"arctic";import{arcticAuthorizationCodeExchange,oauth2Plugin}from"@oglofus/auth";constgoogle=newGoogle(process.env.GOOGLE_CLIENT_ID!,process.env.GOOGLE_CLIENT_SECRET!,process.env.GOOGLE_REDIRECT_URI!);oauth2Plugin<AppUser,"google","given_name"|"family_name">({providers: {google: {exchangeAuthorizationCode: arcticAuthorizationCodeExchange(google),resolveProfile: async({ tokens })=>{constres=awaitfetch("https://openidconnect.googleapis.com/v1/userinfo",{headers: {Authorization: `Bearer ${tokens.accessToken()}`},});constp=awaitres.json()as{sub: string;email?: string;email_verified?: boolean;given_name?: string;family_name?: string;};return{providerUserId: p.sub,email: p.email,emailVerified: p.email_verified,profile: {given_name: p.given_name??"",family_name: p.family_name??"",},};},// pkceRequired defaults to true},},accounts: /* OAuth2AccountAdapter<"google"> */,requiredProfileFields: ["given_name","family_name"]asconst,});constresult=awaitauth.authenticate({method: "oauth2",provider: "google",authorizationCode: "code-from-callback",redirectUri: process.env.GOOGLE_REDIRECT_URI!,codeVerifier: "pkce-code-verifier",idempotencyKey: "oauth-state",});- Method:
"passkey" - Register + authenticate supported.
- The package consumes already-verified passkey results; it does not perform raw WebAuthn attestation/assertion verification.
- Verify WebAuthn with
@simplewebauthn/serveror equivalent first, then pass the verified result intoauth.register(...)/auth.authenticate(...). - Config:
requiredProfileFields,passkeysadapter.
- Method:
"two_factor" - Adds post-primary verification (
TWO_FACTOR_REQUIRED). - This release supports
totpandrecovery_code. - Uses
@oslojs/otpinternally for TOTP verification and enrollment URI generation. - Plugin API:
beginTotpEnrollment(userId)confirmTotpEnrollment({ enrollmentId, code })regenerateRecoveryCodes(userId)
- Method:
"organizations" - Multi-tenant orgs, memberships, role inheritance, feature/limit entitlements, invites.
- Validates role topology on startup (default role, owner role presence, inheritance cycles).
- Method:
"stripe" - User and organization subscriptions with typed billing subjects.
- Checkout session creation, billing portal sessions, webhook verification, local subscription snapshots.
- Plan-level features and limits, trial tracking, and organization entitlement merge support.
- Requires the
stripepackage in your application.
Use discover(...) to support login/register routing logic before full auth:
privatemode: generic non-enumerating response.explicitmode: returns account-aware actions (continue_login,redirect_register,redirect_login).
explicit mode requires an identity adapter.
vp run typecheck
vp run test
vp run pack- Build:
vp run build(outputs todist/) - TypeScript config:
tsconfig.json
ISC License. See the LICENSE file for details.