@ovixa/auth-client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,143 @@
1
+ import {
2
+ OvixaAuthError
3
+ } from "./chunk-UHRF6AFJ.js";
4
+
5
+ // src/middleware/types.ts
6
+ var DEFAULT_COOKIE_OPTIONS = {
7
+ accessTokenCookie: "ovixa_access_token",
8
+ refreshTokenCookie: "ovixa_refresh_token",
9
+ path: "/",
10
+ secure: true,
11
+ httpOnly: true,
12
+ sameSite: "lax"
13
+ };
14
+ function resolveCookieOptions(options) {
15
+ return {
16
+ ...DEFAULT_COOKIE_OPTIONS,
17
+ ...options
18
+ };
19
+ }
20
+ function isPublicRoute(path, publicRoutes) {
21
+ for (const route of publicRoutes) {
22
+ if (route.endsWith("/*")) {
23
+ const prefix = route.slice(0, -2);
24
+ if (path === prefix || path.startsWith(prefix + "/")) {
25
+ return true;
26
+ }
27
+ } else if (route === path) {
28
+ return true;
29
+ }
30
+ }
31
+ return false;
32
+ }
33
+
34
+ // src/middleware/core.ts
35
+ async function checkAuth(auth, adapter, cookieOptions, autoRefresh = true) {
36
+ const options = resolveCookieOptions(cookieOptions);
37
+ const accessToken = adapter.getCookie(options.accessTokenCookie);
38
+ const refreshToken = adapter.getCookie(options.refreshTokenCookie);
39
+ if (!accessToken && !refreshToken) {
40
+ return {
41
+ context: createUnauthenticatedContext()
42
+ };
43
+ }
44
+ if (accessToken) {
45
+ try {
46
+ const result = await auth.verifyToken(accessToken);
47
+ const user = {
48
+ id: result.payload.sub,
49
+ email: result.payload.email,
50
+ emailVerified: result.payload.email_verified
51
+ };
52
+ const session = {
53
+ accessToken,
54
+ refreshToken: refreshToken || "",
55
+ expiresAt: new Date(result.payload.exp * 1e3)
56
+ };
57
+ return {
58
+ context: {
59
+ user,
60
+ session,
61
+ isAuthenticated: true
62
+ }
63
+ };
64
+ } catch (error) {
65
+ if (error instanceof OvixaAuthError && error.code === "TOKEN_EXPIRED" && refreshToken && autoRefresh) {
66
+ return tryRefreshToken(auth, refreshToken);
67
+ }
68
+ if (refreshToken && autoRefresh) {
69
+ return tryRefreshToken(auth, refreshToken);
70
+ }
71
+ return {
72
+ context: createUnauthenticatedContext()
73
+ };
74
+ }
75
+ }
76
+ if (refreshToken && autoRefresh) {
77
+ return tryRefreshToken(auth, refreshToken);
78
+ }
79
+ return {
80
+ context: createUnauthenticatedContext()
81
+ };
82
+ }
83
+ async function tryRefreshToken(auth, refreshToken) {
84
+ try {
85
+ const tokens = await auth.refreshToken(refreshToken);
86
+ const authResult = await auth.toAuthResult(tokens);
87
+ return {
88
+ context: {
89
+ user: authResult.user,
90
+ session: authResult.session,
91
+ isAuthenticated: true
92
+ },
93
+ newTokens: tokens
94
+ };
95
+ } catch {
96
+ return {
97
+ context: createUnauthenticatedContext()
98
+ };
99
+ }
100
+ }
101
+ function createUnauthenticatedContext() {
102
+ return {
103
+ user: null,
104
+ session: null,
105
+ isAuthenticated: false
106
+ };
107
+ }
108
+ function setAuthCookies(adapter, tokens, cookieOptions) {
109
+ const options = resolveCookieOptions(cookieOptions);
110
+ const baseOptions = {
111
+ path: options.path,
112
+ secure: options.secure,
113
+ httpOnly: options.httpOnly,
114
+ sameSite: options.sameSite,
115
+ domain: options.domain
116
+ };
117
+ adapter.setCookie(options.accessTokenCookie, tokens.access_token, {
118
+ ...baseOptions,
119
+ maxAge: tokens.expires_in
120
+ });
121
+ const refreshMaxAge = options.maxAge ?? 30 * 24 * 60 * 60;
122
+ adapter.setCookie(options.refreshTokenCookie, tokens.refresh_token, {
123
+ ...baseOptions,
124
+ maxAge: refreshMaxAge
125
+ });
126
+ }
127
+ function clearAuthCookies(adapter, cookieOptions) {
128
+ const options = resolveCookieOptions(cookieOptions);
129
+ const deleteOptions = {
130
+ path: options.path,
131
+ domain: options.domain
132
+ };
133
+ adapter.deleteCookie(options.accessTokenCookie, deleteOptions);
134
+ adapter.deleteCookie(options.refreshTokenCookie, deleteOptions);
135
+ }
136
+
137
+ export {
138
+ isPublicRoute,
139
+ checkAuth,
140
+ setAuthCookies,
141
+ clearAuthCookies
142
+ };
143
+ //# sourceMappingURL=chunk-Y5NJCTZO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/middleware/types.ts","../src/middleware/core.ts"],"sourcesContent":["/**\n * Middleware types for @ovixa/auth-client\n *\n * Provides generic adapter interfaces and shared types for framework integrations.\n */\n\nimport type { OvixaAuth, User, Session, TokenResponse } from '../index.js';\n\n/**\n * Cookie configuration options for auth middleware.\n */\nexport interface CookieOptions {\n /** Name of the access token cookie (default: 'ovixa_access_token') */\n accessTokenCookie?: string;\n /** Name of the refresh token cookie (default: 'ovixa_refresh_token') */\n refreshTokenCookie?: string;\n /** Cookie path (default: '/') */\n path?: string;\n /** Whether to use secure cookies (default: true) */\n secure?: boolean;\n /** Whether cookies are HTTP-only (default: true) */\n httpOnly?: boolean;\n /** SameSite cookie policy (default: 'lax') */\n sameSite?: 'strict' | 'lax' | 'none';\n /** Cookie domain (optional, defaults to current domain) */\n domain?: string;\n /** Max age for cookies in seconds (optional, defaults to token expiry) */\n maxAge?: number;\n}\n\n/**\n * Options for setting a cookie.\n */\nexport interface SetCookieOptions {\n path: string;\n secure: boolean;\n httpOnly: boolean;\n sameSite: 'strict' | 'lax' | 'none';\n domain?: string;\n maxAge?: number;\n expires?: Date;\n}\n\n/**\n * Options for deleting a cookie.\n */\nexport interface DeleteCookieOptions {\n path: string;\n domain?: string;\n}\n\n/**\n * Configuration for auth middleware.\n */\nexport interface AuthMiddlewareConfig {\n /** OvixaAuth client instance */\n auth: OvixaAuth;\n /** Cookie configuration options */\n cookies?: CookieOptions;\n /** Routes that don't require authentication */\n publicRoutes?: string[];\n /** URL to redirect unauthenticated requests (if not set, returns 401) */\n loginRedirect?: string;\n /** Whether to automatically refresh expired tokens (default: true) */\n autoRefresh?: boolean;\n}\n\n/**\n * Authentication context available in request handlers.\n */\nexport interface AuthContext {\n /** The authenticated user, or null if not authenticated */\n user: User | null;\n /** The current session, or null if not authenticated */\n session: Session | null;\n /** Whether the request is authenticated */\n isAuthenticated: boolean;\n}\n\n/**\n * Generic cookie adapter interface.\n *\n * Implement this interface to add support for additional frameworks.\n * The adapter abstracts cookie operations so the core auth logic\n * remains framework-agnostic.\n *\n * @example\n * ```typescript\n * class HonoCookieAdapter implements CookieAdapter {\n * constructor(private context: HonoContext) {}\n *\n * getCookie(name: string): string | undefined {\n * return this.context.get.cookie(name);\n * }\n *\n * setCookie(name: string, value: string, options: SetCookieOptions): void {\n * this.context.cookie(name, value, options);\n * }\n *\n * deleteCookie(name: string, options: DeleteCookieOptions): void {\n * this.context.cookie(name, '', { ...options, maxAge: 0 });\n * }\n * }\n * ```\n */\nexport interface CookieAdapter {\n /** Get a cookie value by name */\n getCookie(name: string): string | undefined;\n /** Set a cookie with the given value and options */\n setCookie(name: string, value: string, options: SetCookieOptions): void;\n /** Delete a cookie */\n deleteCookie(name: string, options: DeleteCookieOptions): void;\n}\n\n/**\n * Result of authentication check.\n */\nexport interface AuthCheckResult {\n /** Authentication context */\n context: AuthContext;\n /** New tokens if refresh occurred */\n newTokens?: TokenResponse;\n}\n\n/**\n * Default cookie configuration values.\n */\nexport const DEFAULT_COOKIE_OPTIONS: Required<Omit<CookieOptions, 'domain' | 'maxAge'>> = {\n accessTokenCookie: 'ovixa_access_token',\n refreshTokenCookie: 'ovixa_refresh_token',\n path: '/',\n secure: true,\n httpOnly: true,\n sameSite: 'lax',\n};\n\n/**\n * Resolve cookie options with defaults.\n */\nexport function resolveCookieOptions(\n options?: CookieOptions\n): Required<Omit<CookieOptions, 'domain' | 'maxAge'>> & Pick<CookieOptions, 'domain' | 'maxAge'> {\n return {\n ...DEFAULT_COOKIE_OPTIONS,\n ...options,\n };\n}\n\n/**\n * Check if a path matches any of the public routes.\n *\n * Supports:\n * - Exact matches: '/login'\n * - Wildcard suffix: '/api/public/*' matches '/api/public/foo/bar'\n *\n * @param path - The request path to check\n * @param publicRoutes - Array of public route patterns\n * @returns Whether the path is public\n */\nexport function isPublicRoute(path: string, publicRoutes: string[]): boolean {\n for (const route of publicRoutes) {\n if (route.endsWith('/*')) {\n // Wildcard match: '/api/*' matches '/api/foo'\n const prefix = route.slice(0, -2);\n if (path === prefix || path.startsWith(prefix + '/')) {\n return true;\n }\n } else if (route === path) {\n // Exact match\n return true;\n }\n }\n return false;\n}\n","/**\n * Core authentication logic for middleware.\n *\n * This module provides framework-agnostic authentication utilities\n * used by the Astro and Express middleware implementations.\n */\n\nimport type { OvixaAuth, TokenResponse, User, Session } from '../index.js';\nimport { OvixaAuthError } from '../index.js';\nimport type {\n CookieAdapter,\n AuthContext,\n AuthCheckResult,\n CookieOptions,\n SetCookieOptions,\n DeleteCookieOptions,\n} from './types.js';\nimport { resolveCookieOptions } from './types.js';\n\n/**\n * Check authentication status from cookies.\n *\n * This function:\n * 1. Reads the access token from cookies\n * 2. Attempts to verify the access token\n * 3. If expired and autoRefresh is enabled, attempts to refresh using the refresh token\n * 4. Returns the authentication context and any new tokens\n *\n * @param auth - OvixaAuth client instance\n * @param adapter - Cookie adapter for the framework\n * @param cookieOptions - Cookie configuration\n * @param autoRefresh - Whether to automatically refresh expired tokens\n * @returns Authentication check result with context and optional new tokens\n */\nexport async function checkAuth(\n auth: OvixaAuth,\n adapter: CookieAdapter,\n cookieOptions?: CookieOptions,\n autoRefresh = true\n): Promise<AuthCheckResult> {\n const options = resolveCookieOptions(cookieOptions);\n\n const accessToken = adapter.getCookie(options.accessTokenCookie);\n const refreshToken = adapter.getCookie(options.refreshTokenCookie);\n\n // No tokens at all\n if (!accessToken && !refreshToken) {\n return {\n context: createUnauthenticatedContext(),\n };\n }\n\n // Try to verify access token\n if (accessToken) {\n try {\n const result = await auth.verifyToken(accessToken);\n\n const user: User = {\n id: result.payload.sub,\n email: result.payload.email,\n emailVerified: result.payload.email_verified,\n };\n\n const session: Session = {\n accessToken,\n refreshToken: refreshToken || '',\n expiresAt: new Date(result.payload.exp * 1000),\n };\n\n return {\n context: {\n user,\n session,\n isAuthenticated: true,\n },\n };\n } catch (error) {\n // If token is expired and we have a refresh token, try to refresh\n if (\n error instanceof OvixaAuthError &&\n error.code === 'TOKEN_EXPIRED' &&\n refreshToken &&\n autoRefresh\n ) {\n return tryRefreshToken(auth, refreshToken);\n }\n\n // Token is invalid for another reason (bad signature, etc.)\n // Try refresh if we have a refresh token\n if (refreshToken && autoRefresh) {\n return tryRefreshToken(auth, refreshToken);\n }\n\n // No refresh token or refresh disabled, return unauthenticated\n return {\n context: createUnauthenticatedContext(),\n };\n }\n }\n\n // No access token but have refresh token - try to refresh\n if (refreshToken && autoRefresh) {\n return tryRefreshToken(auth, refreshToken);\n }\n\n return {\n context: createUnauthenticatedContext(),\n };\n}\n\n/**\n * Attempt to refresh tokens and return new authentication context.\n */\nasync function tryRefreshToken(auth: OvixaAuth, refreshToken: string): Promise<AuthCheckResult> {\n try {\n const tokens = await auth.refreshToken(refreshToken);\n const authResult = await auth.toAuthResult(tokens);\n\n return {\n context: {\n user: authResult.user,\n session: authResult.session,\n isAuthenticated: true,\n },\n newTokens: tokens,\n };\n } catch {\n // Refresh failed - return unauthenticated\n return {\n context: createUnauthenticatedContext(),\n };\n }\n}\n\n/**\n * Create an unauthenticated context.\n */\nfunction createUnauthenticatedContext(): AuthContext {\n return {\n user: null,\n session: null,\n isAuthenticated: false,\n };\n}\n\n/**\n * Set authentication cookies after login or token refresh.\n *\n * @param adapter - Cookie adapter for the framework\n * @param tokens - Token response from login/refresh\n * @param cookieOptions - Cookie configuration\n */\nexport function setAuthCookies(\n adapter: CookieAdapter,\n tokens: TokenResponse,\n cookieOptions?: CookieOptions\n): void {\n const options = resolveCookieOptions(cookieOptions);\n\n const baseOptions: SetCookieOptions = {\n path: options.path,\n secure: options.secure,\n httpOnly: options.httpOnly,\n sameSite: options.sameSite,\n domain: options.domain,\n };\n\n // Set access token cookie with expiry based on token\n adapter.setCookie(options.accessTokenCookie, tokens.access_token, {\n ...baseOptions,\n maxAge: tokens.expires_in,\n });\n\n // Set refresh token cookie with longer expiry (or custom maxAge)\n // Refresh tokens typically have longer lifetimes than access tokens\n // Default to 30 days if no maxAge specified\n const refreshMaxAge = options.maxAge ?? 30 * 24 * 60 * 60; // 30 days in seconds\n adapter.setCookie(options.refreshTokenCookie, tokens.refresh_token, {\n ...baseOptions,\n maxAge: refreshMaxAge,\n });\n}\n\n/**\n * Clear authentication cookies on logout.\n *\n * @param adapter - Cookie adapter for the framework\n * @param cookieOptions - Cookie configuration\n */\nexport function clearAuthCookies(adapter: CookieAdapter, cookieOptions?: CookieOptions): void {\n const options = resolveCookieOptions(cookieOptions);\n\n const deleteOptions: DeleteCookieOptions = {\n path: options.path,\n domain: options.domain,\n };\n\n adapter.deleteCookie(options.accessTokenCookie, deleteOptions);\n adapter.deleteCookie(options.refreshTokenCookie, deleteOptions);\n}\n"],"mappings":";;;;;AA+HO,IAAM,yBAA6E;AAAA,EACxF,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,UAAU;AACZ;AAKO,SAAS,qBACd,SAC+F;AAC/F,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AACF;AAaO,SAAS,cAAc,MAAc,cAAiC;AAC3E,aAAW,SAAS,cAAc;AAChC,QAAI,MAAM,SAAS,IAAI,GAAG;AAExB,YAAM,SAAS,MAAM,MAAM,GAAG,EAAE;AAChC,UAAI,SAAS,UAAU,KAAK,WAAW,SAAS,GAAG,GAAG;AACpD,eAAO;AAAA,MACT;AAAA,IACF,WAAW,UAAU,MAAM;AAEzB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;;;AC3IA,eAAsB,UACpB,MACA,SACA,eACA,cAAc,MACY;AAC1B,QAAM,UAAU,qBAAqB,aAAa;AAElD,QAAM,cAAc,QAAQ,UAAU,QAAQ,iBAAiB;AAC/D,QAAM,eAAe,QAAQ,UAAU,QAAQ,kBAAkB;AAGjE,MAAI,CAAC,eAAe,CAAC,cAAc;AACjC,WAAO;AAAA,MACL,SAAS,6BAA6B;AAAA,IACxC;AAAA,EACF;AAGA,MAAI,aAAa;AACf,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,YAAY,WAAW;AAEjD,YAAM,OAAa;AAAA,QACjB,IAAI,OAAO,QAAQ;AAAA,QACnB,OAAO,OAAO,QAAQ;AAAA,QACtB,eAAe,OAAO,QAAQ;AAAA,MAChC;AAEA,YAAM,UAAmB;AAAA,QACvB;AAAA,QACA,cAAc,gBAAgB;AAAA,QAC9B,WAAW,IAAI,KAAK,OAAO,QAAQ,MAAM,GAAI;AAAA,MAC/C;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA,iBAAiB;AAAA,QACnB;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AAEd,UACE,iBAAiB,kBACjB,MAAM,SAAS,mBACf,gBACA,aACA;AACA,eAAO,gBAAgB,MAAM,YAAY;AAAA,MAC3C;AAIA,UAAI,gBAAgB,aAAa;AAC/B,eAAO,gBAAgB,MAAM,YAAY;AAAA,MAC3C;AAGA,aAAO;AAAA,QACL,SAAS,6BAA6B;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAGA,MAAI,gBAAgB,aAAa;AAC/B,WAAO,gBAAgB,MAAM,YAAY;AAAA,EAC3C;AAEA,SAAO;AAAA,IACL,SAAS,6BAA6B;AAAA,EACxC;AACF;AAKA,eAAe,gBAAgB,MAAiB,cAAgD;AAC9F,MAAI;AACF,UAAM,SAAS,MAAM,KAAK,aAAa,YAAY;AACnD,UAAM,aAAa,MAAM,KAAK,aAAa,MAAM;AAEjD,WAAO;AAAA,MACL,SAAS;AAAA,QACP,MAAM,WAAW;AAAA,QACjB,SAAS,WAAW;AAAA,QACpB,iBAAiB;AAAA,MACnB;AAAA,MACA,WAAW;AAAA,IACb;AAAA,EACF,QAAQ;AAEN,WAAO;AAAA,MACL,SAAS,6BAA6B;AAAA,IACxC;AAAA,EACF;AACF;AAKA,SAAS,+BAA4C;AACnD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,iBAAiB;AAAA,EACnB;AACF;AASO,SAAS,eACd,SACA,QACA,eACM;AACN,QAAM,UAAU,qBAAqB,aAAa;AAElD,QAAM,cAAgC;AAAA,IACpC,MAAM,QAAQ;AAAA,IACd,QAAQ,QAAQ;AAAA,IAChB,UAAU,QAAQ;AAAA,IAClB,UAAU,QAAQ;AAAA,IAClB,QAAQ,QAAQ;AAAA,EAClB;AAGA,UAAQ,UAAU,QAAQ,mBAAmB,OAAO,cAAc;AAAA,IAChE,GAAG;AAAA,IACH,QAAQ,OAAO;AAAA,EACjB,CAAC;AAKD,QAAM,gBAAgB,QAAQ,UAAU,KAAK,KAAK,KAAK;AACvD,UAAQ,UAAU,QAAQ,oBAAoB,OAAO,eAAe;AAAA,IAClE,GAAG;AAAA,IACH,QAAQ;AAAA,EACV,CAAC;AACH;AAQO,SAAS,iBAAiB,SAAwB,eAAqC;AAC5F,QAAM,UAAU,qBAAqB,aAAa;AAElD,QAAM,gBAAqC;AAAA,IACzC,MAAM,QAAQ;AAAA,IACd,QAAQ,QAAQ;AAAA,EAClB;AAEA,UAAQ,aAAa,QAAQ,mBAAmB,aAAa;AAC7D,UAAQ,aAAa,QAAQ,oBAAoB,aAAa;AAChE;","names":[]}
@@ -0,0 +1,498 @@
1
+ import { JWTPayload, JWTHeaderParameters } from 'jose';
2
+
3
+ /**
4
+ * @ovixa/auth-client
5
+ *
6
+ * Client SDK for Ovixa Auth service.
7
+ * Provides authentication, token verification, and session management.
8
+ */
9
+
10
+ /**
11
+ * Configuration options for the OvixaAuth client.
12
+ */
13
+ interface AuthClientConfig {
14
+ /** The base URL of the Ovixa Auth service */
15
+ authUrl: string;
16
+ /** The realm ID to authenticate against */
17
+ realmId: string;
18
+ /** Your application's client secret (for server-side use only) */
19
+ clientSecret?: string;
20
+ /** Cache duration for JWKS in milliseconds (defaults to 1 hour) */
21
+ jwksCacheTtl?: number;
22
+ }
23
+ /**
24
+ * JWT claims for an Ovixa access token.
25
+ */
26
+ interface AccessTokenPayload extends JWTPayload {
27
+ /** Subject (user ID) */
28
+ sub: string;
29
+ /** User's email address */
30
+ email: string;
31
+ /** Whether the user's email has been verified */
32
+ email_verified: boolean;
33
+ /** Issued at timestamp */
34
+ iat: number;
35
+ /** Expiration timestamp */
36
+ exp: number;
37
+ /** Issuer */
38
+ iss: string;
39
+ /** Audience (realm ID) */
40
+ aud: string;
41
+ }
42
+ /**
43
+ * Result of a successful token verification.
44
+ */
45
+ interface VerifyResult {
46
+ /** The decoded token payload */
47
+ payload: AccessTokenPayload;
48
+ /** The protected header */
49
+ protectedHeader: JWTHeaderParameters;
50
+ }
51
+ /**
52
+ * Token response from the auth service.
53
+ */
54
+ interface TokenResponse {
55
+ /** The access token (JWT) */
56
+ access_token: string;
57
+ /** The refresh token (JWT) */
58
+ refresh_token: string;
59
+ /** Token type (always "Bearer") */
60
+ token_type: 'Bearer';
61
+ /** Access token expiration time in seconds */
62
+ expires_in: number;
63
+ /** Whether this is a new user (only present in OAuth callback) */
64
+ is_new_user?: boolean;
65
+ }
66
+ /**
67
+ * User information extracted from token payload.
68
+ */
69
+ interface User {
70
+ /** User ID (UUID) */
71
+ id: string;
72
+ /** User's email address */
73
+ email: string;
74
+ /** Whether the email has been verified */
75
+ emailVerified: boolean;
76
+ }
77
+ /**
78
+ * Session information containing tokens and expiry.
79
+ */
80
+ interface Session {
81
+ /** The access token (JWT) */
82
+ accessToken: string;
83
+ /** The refresh token for obtaining new access tokens */
84
+ refreshToken: string;
85
+ /** When the access token expires */
86
+ expiresAt: Date;
87
+ }
88
+ /**
89
+ * Combined authentication result with user and session data.
90
+ */
91
+ interface AuthResult {
92
+ /** The authenticated user */
93
+ user: User;
94
+ /** The session tokens */
95
+ session: Session;
96
+ /** Whether this is a new user (only set for OAuth flows) */
97
+ isNewUser?: boolean;
98
+ }
99
+ /**
100
+ * Options for signup.
101
+ */
102
+ interface SignupOptions {
103
+ /** User's email address */
104
+ email: string;
105
+ /** Password meeting requirements */
106
+ password: string;
107
+ /** Optional redirect URI after email verification */
108
+ redirectUri?: string;
109
+ }
110
+ /**
111
+ * Response from signup endpoint.
112
+ */
113
+ interface SignupResponse {
114
+ /** Whether the operation succeeded */
115
+ success: boolean;
116
+ /** Status message */
117
+ message: string;
118
+ }
119
+ /**
120
+ * Options for login.
121
+ */
122
+ interface LoginOptions {
123
+ /** User's email address */
124
+ email: string;
125
+ /** User's password */
126
+ password: string;
127
+ }
128
+ /**
129
+ * Options for email verification.
130
+ */
131
+ interface VerifyEmailOptions {
132
+ /** Verification token from email */
133
+ token: string;
134
+ }
135
+ /**
136
+ * Options for resending verification email.
137
+ */
138
+ interface ResendVerificationOptions {
139
+ /** User's email address */
140
+ email: string;
141
+ /** Optional redirect URI after verification */
142
+ redirectUri?: string;
143
+ }
144
+ /**
145
+ * Generic success response.
146
+ */
147
+ interface SuccessResponse {
148
+ /** Whether the operation succeeded */
149
+ success: boolean;
150
+ /** Optional status message */
151
+ message?: string;
152
+ }
153
+ /**
154
+ * Options for forgot password request.
155
+ */
156
+ interface ForgotPasswordOptions {
157
+ /** User's email address */
158
+ email: string;
159
+ /** Optional redirect URI for password reset page */
160
+ redirectUri?: string;
161
+ }
162
+ /**
163
+ * Options for password reset.
164
+ */
165
+ interface ResetPasswordOptions {
166
+ /** Reset token from email */
167
+ token: string;
168
+ /** New password */
169
+ password: string;
170
+ }
171
+ /**
172
+ * Supported OAuth providers.
173
+ */
174
+ type OAuthProvider = 'google' | 'github';
175
+ /**
176
+ * Options for generating OAuth URL.
177
+ */
178
+ interface GetOAuthUrlOptions {
179
+ /** OAuth provider */
180
+ provider: OAuthProvider;
181
+ /** Redirect URI after OAuth completes */
182
+ redirectUri: string;
183
+ }
184
+ /**
185
+ * Error thrown by OvixaAuth operations.
186
+ */
187
+ declare class OvixaAuthError extends Error {
188
+ readonly code: string;
189
+ readonly statusCode?: number | undefined;
190
+ constructor(message: string, code: string, statusCode?: number | undefined);
191
+ }
192
+ /**
193
+ * OvixaAuth client for authenticating with the Ovixa Auth service.
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * const auth = new OvixaAuth({
198
+ * authUrl: 'https://auth.ovixa.io',
199
+ * realmId: 'your-realm-id',
200
+ * clientSecret: 'your-client-secret', // Optional, for server-side use
201
+ * });
202
+ *
203
+ * // Verify a token
204
+ * const result = await auth.verifyToken(accessToken);
205
+ * console.log(result.payload.email);
206
+ *
207
+ * // Refresh tokens
208
+ * const tokens = await auth.refreshToken(refreshToken);
209
+ * ```
210
+ */
211
+ declare class OvixaAuth {
212
+ private config;
213
+ private jwksCache;
214
+ constructor(config: AuthClientConfig);
215
+ /** Get the configured auth URL */
216
+ get authUrl(): string;
217
+ /** Get the configured realm ID */
218
+ get realmId(): string;
219
+ /**
220
+ * Get the JWKS URL for the auth service.
221
+ */
222
+ get jwksUrl(): string;
223
+ /**
224
+ * Get the JWKS fetcher, creating a new one if necessary.
225
+ * The fetcher is cached based on the configured TTL.
226
+ */
227
+ private getJwksFetcher;
228
+ /**
229
+ * Verify an access token and return the decoded payload.
230
+ *
231
+ * This method fetches the public key from the JWKS endpoint (with caching)
232
+ * and verifies the token's signature and claims.
233
+ *
234
+ * @param token - The access token (JWT) to verify
235
+ * @returns The verified token payload and header
236
+ * @throws {OvixaAuthError} If verification fails
237
+ *
238
+ * @example
239
+ * ```typescript
240
+ * try {
241
+ * const result = await auth.verifyToken(accessToken);
242
+ * console.log('User ID:', result.payload.sub);
243
+ * console.log('Email:', result.payload.email);
244
+ * } catch (error) {
245
+ * if (error instanceof OvixaAuthError) {
246
+ * console.error('Token verification failed:', error.code);
247
+ * }
248
+ * }
249
+ * ```
250
+ */
251
+ verifyToken(token: string): Promise<VerifyResult>;
252
+ /**
253
+ * Refresh an access token using a refresh token.
254
+ *
255
+ * This method exchanges a valid refresh token for a new access token
256
+ * and a new refresh token (token rotation).
257
+ *
258
+ * @param refreshToken - The refresh token to exchange
259
+ * @returns New token response with access and refresh tokens
260
+ * @throws {OvixaAuthError} If the refresh fails
261
+ *
262
+ * @example
263
+ * ```typescript
264
+ * try {
265
+ * const tokens = await auth.refreshToken(currentRefreshToken);
266
+ * // Store the new tokens
267
+ * saveTokens(tokens.access_token, tokens.refresh_token);
268
+ * } catch (error) {
269
+ * if (error instanceof OvixaAuthError) {
270
+ * // Refresh token is invalid or expired - user must re-authenticate
271
+ * redirectToLogin();
272
+ * }
273
+ * }
274
+ * ```
275
+ */
276
+ refreshToken(refreshToken: string): Promise<TokenResponse>;
277
+ /**
278
+ * Invalidate the cached JWKS fetcher.
279
+ * Call this if you need to force a refresh of the public keys.
280
+ */
281
+ clearJwksCache(): void;
282
+ /**
283
+ * Create a new user account.
284
+ *
285
+ * After signup, a verification email is sent. The user must verify their
286
+ * email before they can log in.
287
+ *
288
+ * @param options - Signup options
289
+ * @returns Signup response indicating success
290
+ * @throws {OvixaAuthError} If signup fails
291
+ *
292
+ * @example
293
+ * ```typescript
294
+ * try {
295
+ * await auth.signup({
296
+ * email: 'user@example.com',
297
+ * password: 'SecurePassword123!',
298
+ * redirectUri: 'https://myapp.com/verify-callback',
299
+ * });
300
+ * console.log('Verification email sent!');
301
+ * } catch (error) {
302
+ * if (error instanceof OvixaAuthError) {
303
+ * if (error.code === 'EMAIL_ALREADY_EXISTS') {
304
+ * console.error('Email is already registered');
305
+ * }
306
+ * }
307
+ * }
308
+ * ```
309
+ */
310
+ signup(options: SignupOptions): Promise<SignupResponse>;
311
+ /**
312
+ * Authenticate a user with email and password.
313
+ *
314
+ * @param options - Login options
315
+ * @returns Token response with access and refresh tokens
316
+ * @throws {OvixaAuthError} If login fails
317
+ *
318
+ * @example
319
+ * ```typescript
320
+ * try {
321
+ * const tokens = await auth.login({
322
+ * email: 'user@example.com',
323
+ * password: 'SecurePassword123!',
324
+ * });
325
+ * console.log('Logged in!', tokens.access_token);
326
+ * } catch (error) {
327
+ * if (error instanceof OvixaAuthError) {
328
+ * if (error.code === 'EMAIL_NOT_VERIFIED') {
329
+ * console.error('Please verify your email first');
330
+ * } else if (error.code === 'INVALID_CREDENTIALS') {
331
+ * console.error('Invalid email or password');
332
+ * }
333
+ * }
334
+ * }
335
+ * ```
336
+ */
337
+ login(options: LoginOptions): Promise<TokenResponse>;
338
+ /**
339
+ * Verify an email address using a verification token.
340
+ *
341
+ * This is the API flow that returns tokens. For browser redirect flow,
342
+ * use `GET /verify` directly.
343
+ *
344
+ * @param options - Verification options
345
+ * @returns Token response with access and refresh tokens
346
+ * @throws {OvixaAuthError} If verification fails
347
+ *
348
+ * @example
349
+ * ```typescript
350
+ * // Get token from URL query params after clicking email link
351
+ * const token = new URLSearchParams(window.location.search).get('token');
352
+ *
353
+ * try {
354
+ * const tokens = await auth.verifyEmail({ token });
355
+ * console.log('Email verified! Logged in.');
356
+ * } catch (error) {
357
+ * if (error instanceof OvixaAuthError && error.code === 'INVALID_TOKEN') {
358
+ * console.error('Invalid or expired verification link');
359
+ * }
360
+ * }
361
+ * ```
362
+ */
363
+ verifyEmail(options: VerifyEmailOptions): Promise<TokenResponse>;
364
+ /**
365
+ * Resend a verification email for an unverified account.
366
+ *
367
+ * @param options - Resend options
368
+ * @returns Success response
369
+ * @throws {OvixaAuthError} If request fails
370
+ *
371
+ * @example
372
+ * ```typescript
373
+ * await auth.resendVerification({
374
+ * email: 'user@example.com',
375
+ * redirectUri: 'https://myapp.com/verify-callback',
376
+ * });
377
+ * console.log('Verification email sent!');
378
+ * ```
379
+ */
380
+ resendVerification(options: ResendVerificationOptions): Promise<SuccessResponse>;
381
+ /**
382
+ * Request a password reset email.
383
+ *
384
+ * Note: This endpoint always returns success to prevent email enumeration.
385
+ *
386
+ * @param options - Forgot password options
387
+ * @returns Success response
388
+ * @throws {OvixaAuthError} If request fails
389
+ *
390
+ * @example
391
+ * ```typescript
392
+ * await auth.forgotPassword({
393
+ * email: 'user@example.com',
394
+ * redirectUri: 'https://myapp.com/reset-password',
395
+ * });
396
+ * console.log('If the email exists, a reset link has been sent.');
397
+ * ```
398
+ */
399
+ forgotPassword(options: ForgotPasswordOptions): Promise<SuccessResponse>;
400
+ /**
401
+ * Reset password using a reset token.
402
+ *
403
+ * @param options - Reset password options
404
+ * @returns Success response
405
+ * @throws {OvixaAuthError} If reset fails
406
+ *
407
+ * @example
408
+ * ```typescript
409
+ * // Get token from URL query params
410
+ * const token = new URLSearchParams(window.location.search).get('token');
411
+ *
412
+ * try {
413
+ * await auth.resetPassword({
414
+ * token,
415
+ * password: 'NewSecurePassword123!',
416
+ * });
417
+ * console.log('Password reset successfully!');
418
+ * } catch (error) {
419
+ * if (error instanceof OvixaAuthError) {
420
+ * if (error.code === 'INVALID_TOKEN') {
421
+ * console.error('Invalid or expired reset link');
422
+ * } else if (error.code === 'WEAK_PASSWORD') {
423
+ * console.error('Password does not meet requirements');
424
+ * }
425
+ * }
426
+ * }
427
+ * ```
428
+ */
429
+ resetPassword(options: ResetPasswordOptions): Promise<SuccessResponse>;
430
+ /**
431
+ * Revoke a refresh token (logout).
432
+ *
433
+ * @param refreshToken - The refresh token to revoke
434
+ * @returns Success response
435
+ * @throws {OvixaAuthError} If logout fails
436
+ *
437
+ * @example
438
+ * ```typescript
439
+ * await auth.logout(currentRefreshToken);
440
+ * // Clear local token storage
441
+ * localStorage.removeItem('refresh_token');
442
+ * localStorage.removeItem('access_token');
443
+ * ```
444
+ */
445
+ logout(refreshToken: string): Promise<SuccessResponse>;
446
+ /**
447
+ * Generate an OAuth authorization URL.
448
+ *
449
+ * Redirect the user to this URL to start the OAuth flow. After authentication,
450
+ * the user will be redirected back to your `redirectUri` with tokens.
451
+ *
452
+ * @param options - OAuth URL options
453
+ * @returns The full OAuth authorization URL
454
+ *
455
+ * @example
456
+ * ```typescript
457
+ * const googleAuthUrl = auth.getOAuthUrl({
458
+ * provider: 'google',
459
+ * redirectUri: 'https://myapp.com/auth/callback',
460
+ * });
461
+ *
462
+ * // Redirect user to start OAuth flow
463
+ * window.location.href = googleAuthUrl;
464
+ * ```
465
+ */
466
+ getOAuthUrl(options: GetOAuthUrlOptions): string;
467
+ /**
468
+ * Transform a token response into an AuthResult with user and session data.
469
+ *
470
+ * This method decodes the access token to extract user information and
471
+ * creates a structured result object.
472
+ *
473
+ * @param tokenResponse - The token response from login, verify, or refresh
474
+ * @returns AuthResult with user and session data
475
+ * @throws {OvixaAuthError} If the access token cannot be decoded
476
+ *
477
+ * @example
478
+ * ```typescript
479
+ * const tokens = await auth.login({ email, password });
480
+ * const result = await auth.toAuthResult(tokens);
481
+ *
482
+ * console.log('User ID:', result.user.id);
483
+ * console.log('Email:', result.user.email);
484
+ * console.log('Expires at:', result.session.expiresAt);
485
+ * ```
486
+ */
487
+ toAuthResult(tokenResponse: TokenResponse): Promise<AuthResult>;
488
+ /**
489
+ * Make an authenticated POST request to the auth service.
490
+ */
491
+ private makeRequest;
492
+ /**
493
+ * Map HTTP status codes to error codes.
494
+ */
495
+ private mapHttpStatusToErrorCode;
496
+ }
497
+
498
+ export { type AccessTokenPayload, type AuthClientConfig, type AuthResult, type ForgotPasswordOptions, type GetOAuthUrlOptions, type LoginOptions, type OAuthProvider, OvixaAuth, OvixaAuthError, type ResendVerificationOptions, type ResetPasswordOptions, type Session, type SignupOptions, type SignupResponse, type SuccessResponse, type TokenResponse, type User, type VerifyEmailOptions, type VerifyResult };
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ import {
2
+ OvixaAuth,
3
+ OvixaAuthError
4
+ } from "./chunk-UHRF6AFJ.js";
5
+ export {
6
+ OvixaAuth,
7
+ OvixaAuthError
8
+ };
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}