@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,155 @@
1
+ import { TokenResponse } from '../index.js';
2
+ import { A as AuthMiddlewareConfig, a as AuthContext, C as CookieOptions } from '../types-Czfah64-.js';
3
+ import 'jose';
4
+
5
+ /**
6
+ * Astro middleware for @ovixa/auth-client
7
+ *
8
+ * Provides authentication middleware for Astro applications using cookie-based sessions.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * // src/middleware.ts
13
+ * import { createAstroAuth } from '@ovixa/auth-client/astro';
14
+ * import { auth } from './lib/auth';
15
+ *
16
+ * export const onRequest = createAstroAuth({
17
+ * auth,
18
+ * publicRoutes: ['/', '/login', '/signup', '/api/public/*'],
19
+ * loginRedirect: '/login',
20
+ * });
21
+ *
22
+ * // Access in pages/layouts:
23
+ * const { user, isAuthenticated } = Astro.locals.auth;
24
+ * ```
25
+ */
26
+
27
+ /**
28
+ * Astro APIContext type (minimal subset we need).
29
+ * We use this instead of importing from 'astro' to avoid requiring it as a dependency.
30
+ */
31
+ interface AstroAPIContext {
32
+ url: URL;
33
+ cookies: AstroCookies;
34
+ locals: AstroLocals;
35
+ redirect: (path: string, status?: number) => Response;
36
+ }
37
+ interface AstroCookies {
38
+ get(name: string): {
39
+ value: string;
40
+ } | undefined;
41
+ set(name: string, value: string, options?: AstroCookieSetOptions): void;
42
+ delete(name: string, options?: AstroCookieDeleteOptions): void;
43
+ }
44
+ interface AstroCookieSetOptions {
45
+ path?: string;
46
+ secure?: boolean;
47
+ httpOnly?: boolean;
48
+ sameSite?: 'strict' | 'lax' | 'none';
49
+ domain?: string;
50
+ maxAge?: number;
51
+ expires?: Date;
52
+ }
53
+ interface AstroCookieDeleteOptions {
54
+ path?: string;
55
+ domain?: string;
56
+ }
57
+ interface AstroLocals {
58
+ auth?: AuthContext;
59
+ [key: string]: unknown;
60
+ }
61
+ /**
62
+ * Astro middleware handler type.
63
+ */
64
+ type AstroMiddlewareHandler = (context: AstroAPIContext, next: () => Promise<Response>) => Promise<Response>;
65
+ /**
66
+ * Create Astro authentication middleware.
67
+ *
68
+ * This middleware:
69
+ * - Checks authentication status from cookies on each request
70
+ * - Automatically refreshes expired access tokens using refresh tokens
71
+ * - Sets `Astro.locals.auth` with the authentication context
72
+ * - Optionally redirects unauthenticated requests to a login page
73
+ * - Allows public routes to bypass authentication
74
+ *
75
+ * @param config - Middleware configuration
76
+ * @returns Astro middleware handler
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * // src/middleware.ts
81
+ * import { createAstroAuth } from '@ovixa/auth-client/astro';
82
+ * import { OvixaAuth } from '@ovixa/auth-client';
83
+ *
84
+ * const auth = new OvixaAuth({
85
+ * authUrl: import.meta.env.AUTH_URL,
86
+ * realmId: import.meta.env.AUTH_REALM_ID,
87
+ * });
88
+ *
89
+ * export const onRequest = createAstroAuth({
90
+ * auth,
91
+ * publicRoutes: ['/', '/login', '/signup'],
92
+ * loginRedirect: '/login',
93
+ * cookies: {
94
+ * secure: import.meta.env.PROD,
95
+ * },
96
+ * });
97
+ * ```
98
+ */
99
+ declare function createAstroAuth(config: AuthMiddlewareConfig): AstroMiddlewareHandler;
100
+ /**
101
+ * Set authentication cookies after login.
102
+ *
103
+ * Call this after a successful login to store tokens in cookies.
104
+ *
105
+ * @param context - Astro API context (from Astro global or API route)
106
+ * @param tokens - Token response from login/verify/OAuth callback
107
+ * @param cookieOptions - Optional cookie configuration overrides
108
+ *
109
+ * @example
110
+ * ```typescript
111
+ * // src/pages/api/login.ts
112
+ * import { setAstroAuthCookies } from '@ovixa/auth-client/astro';
113
+ * import { auth } from '../../lib/auth';
114
+ *
115
+ * export async function POST({ request, cookies }: APIContext) {
116
+ * const { email, password } = await request.json();
117
+ * const tokens = await auth.login({ email, password });
118
+ *
119
+ * setAstroAuthCookies({ cookies }, tokens);
120
+ *
121
+ * return new Response(JSON.stringify({ success: true }));
122
+ * }
123
+ * ```
124
+ */
125
+ declare function setAstroAuthCookies(context: Pick<AstroAPIContext, 'cookies'>, tokens: TokenResponse, cookieOptions?: CookieOptions): void;
126
+ /**
127
+ * Clear authentication cookies on logout.
128
+ *
129
+ * Call this to log out the user by removing their session cookies.
130
+ *
131
+ * @param context - Astro API context
132
+ * @param cookieOptions - Optional cookie configuration overrides
133
+ *
134
+ * @example
135
+ * ```typescript
136
+ * // src/pages/api/logout.ts
137
+ * import { clearAstroAuthCookies } from '@ovixa/auth-client/astro';
138
+ * import { auth } from '../../lib/auth';
139
+ *
140
+ * export async function POST({ cookies, locals }: APIContext) {
141
+ * // Revoke refresh token on server
142
+ * if (locals.auth?.session?.refreshToken) {
143
+ * await auth.logout(locals.auth.session.refreshToken);
144
+ * }
145
+ *
146
+ * // Clear cookies
147
+ * clearAstroAuthCookies({ cookies });
148
+ *
149
+ * return new Response(JSON.stringify({ success: true }));
150
+ * }
151
+ * ```
152
+ */
153
+ declare function clearAstroAuthCookies(context: Pick<AstroAPIContext, 'cookies'>, cookieOptions?: CookieOptions): void;
154
+
155
+ export { AuthContext, AuthMiddlewareConfig, CookieOptions, clearAstroAuthCookies, createAstroAuth, setAstroAuthCookies };
@@ -0,0 +1,75 @@
1
+ import {
2
+ checkAuth,
3
+ clearAuthCookies,
4
+ isPublicRoute,
5
+ setAuthCookies
6
+ } from "../chunk-Y5NJCTZO.js";
7
+ import "../chunk-UHRF6AFJ.js";
8
+
9
+ // src/middleware/astro.ts
10
+ var AstroCookieAdapter = class {
11
+ constructor(cookies) {
12
+ this.cookies = cookies;
13
+ }
14
+ getCookie(name) {
15
+ return this.cookies.get(name)?.value;
16
+ }
17
+ setCookie(name, value, options) {
18
+ this.cookies.set(name, value, {
19
+ path: options.path,
20
+ secure: options.secure,
21
+ httpOnly: options.httpOnly,
22
+ sameSite: options.sameSite,
23
+ domain: options.domain,
24
+ maxAge: options.maxAge,
25
+ expires: options.expires
26
+ });
27
+ }
28
+ deleteCookie(name, options) {
29
+ this.cookies.delete(name, {
30
+ path: options.path,
31
+ domain: options.domain
32
+ });
33
+ }
34
+ };
35
+ function createAstroAuth(config) {
36
+ const { auth, cookies, publicRoutes = [], loginRedirect, autoRefresh = true } = config;
37
+ return async (context, next) => {
38
+ const path = context.url.pathname;
39
+ const isPublic = isPublicRoute(path, publicRoutes);
40
+ const adapter = new AstroCookieAdapter(context.cookies);
41
+ const result = await checkAuth(auth, adapter, cookies, autoRefresh);
42
+ if (result.newTokens) {
43
+ setAuthCookies(adapter, result.newTokens, cookies);
44
+ }
45
+ context.locals.auth = result.context;
46
+ if (result.context.isAuthenticated || isPublic) {
47
+ return next();
48
+ }
49
+ if (loginRedirect) {
50
+ const returnUrl = encodeURIComponent(context.url.pathname + context.url.search);
51
+ const redirectUrl = `${loginRedirect}?returnUrl=${returnUrl}`;
52
+ return context.redirect(redirectUrl, 302);
53
+ }
54
+ return new Response(JSON.stringify({ error: "Unauthorized" }), {
55
+ status: 401,
56
+ headers: {
57
+ "Content-Type": "application/json"
58
+ }
59
+ });
60
+ };
61
+ }
62
+ function setAstroAuthCookies(context, tokens, cookieOptions) {
63
+ const adapter = new AstroCookieAdapter(context.cookies);
64
+ setAuthCookies(adapter, tokens, cookieOptions);
65
+ }
66
+ function clearAstroAuthCookies(context, cookieOptions) {
67
+ const adapter = new AstroCookieAdapter(context.cookies);
68
+ clearAuthCookies(adapter, cookieOptions);
69
+ }
70
+ export {
71
+ clearAstroAuthCookies,
72
+ createAstroAuth,
73
+ setAstroAuthCookies
74
+ };
75
+ //# sourceMappingURL=astro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/middleware/astro.ts"],"sourcesContent":["/**\n * Astro middleware for @ovixa/auth-client\n *\n * Provides authentication middleware for Astro applications using cookie-based sessions.\n *\n * @example\n * ```typescript\n * // src/middleware.ts\n * import { createAstroAuth } from '@ovixa/auth-client/astro';\n * import { auth } from './lib/auth';\n *\n * export const onRequest = createAstroAuth({\n * auth,\n * publicRoutes: ['/', '/login', '/signup', '/api/public/*'],\n * loginRedirect: '/login',\n * });\n *\n * // Access in pages/layouts:\n * const { user, isAuthenticated } = Astro.locals.auth;\n * ```\n */\n\nimport type { TokenResponse } from '../index.js';\nimport type {\n AuthMiddlewareConfig,\n AuthContext,\n CookieAdapter,\n SetCookieOptions,\n DeleteCookieOptions,\n CookieOptions,\n} from './types.js';\nimport { isPublicRoute } from './types.js';\nimport {\n checkAuth,\n setAuthCookies as coreSetAuthCookies,\n clearAuthCookies as coreClearAuthCookies,\n} from './core.js';\n\n/**\n * Astro APIContext type (minimal subset we need).\n * We use this instead of importing from 'astro' to avoid requiring it as a dependency.\n */\ninterface AstroAPIContext {\n url: URL;\n cookies: AstroCookies;\n locals: AstroLocals;\n redirect: (path: string, status?: number) => Response;\n}\n\ninterface AstroCookies {\n get(name: string): { value: string } | undefined;\n set(name: string, value: string, options?: AstroCookieSetOptions): void;\n delete(name: string, options?: AstroCookieDeleteOptions): void;\n}\n\ninterface AstroCookieSetOptions {\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\ninterface AstroCookieDeleteOptions {\n path?: string;\n domain?: string;\n}\n\ninterface AstroLocals {\n auth?: AuthContext;\n [key: string]: unknown;\n}\n\n/**\n * Astro middleware handler type.\n */\ntype AstroMiddlewareHandler = (\n context: AstroAPIContext,\n next: () => Promise<Response>\n) => Promise<Response>;\n\n/**\n * Cookie adapter for Astro's cookie API.\n */\nclass AstroCookieAdapter implements CookieAdapter {\n constructor(private cookies: AstroCookies) {}\n\n getCookie(name: string): string | undefined {\n return this.cookies.get(name)?.value;\n }\n\n setCookie(name: string, value: string, options: SetCookieOptions): void {\n this.cookies.set(name, value, {\n path: options.path,\n secure: options.secure,\n httpOnly: options.httpOnly,\n sameSite: options.sameSite,\n domain: options.domain,\n maxAge: options.maxAge,\n expires: options.expires,\n });\n }\n\n deleteCookie(name: string, options: DeleteCookieOptions): void {\n this.cookies.delete(name, {\n path: options.path,\n domain: options.domain,\n });\n }\n}\n\n/**\n * Create Astro authentication middleware.\n *\n * This middleware:\n * - Checks authentication status from cookies on each request\n * - Automatically refreshes expired access tokens using refresh tokens\n * - Sets `Astro.locals.auth` with the authentication context\n * - Optionally redirects unauthenticated requests to a login page\n * - Allows public routes to bypass authentication\n *\n * @param config - Middleware configuration\n * @returns Astro middleware handler\n *\n * @example\n * ```typescript\n * // src/middleware.ts\n * import { createAstroAuth } from '@ovixa/auth-client/astro';\n * import { OvixaAuth } from '@ovixa/auth-client';\n *\n * const auth = new OvixaAuth({\n * authUrl: import.meta.env.AUTH_URL,\n * realmId: import.meta.env.AUTH_REALM_ID,\n * });\n *\n * export const onRequest = createAstroAuth({\n * auth,\n * publicRoutes: ['/', '/login', '/signup'],\n * loginRedirect: '/login',\n * cookies: {\n * secure: import.meta.env.PROD,\n * },\n * });\n * ```\n */\nexport function createAstroAuth(config: AuthMiddlewareConfig): AstroMiddlewareHandler {\n const { auth, cookies, publicRoutes = [], loginRedirect, autoRefresh = true } = config;\n\n return async (context: AstroAPIContext, next: () => Promise<Response>): Promise<Response> => {\n const path = context.url.pathname;\n\n // Check if this is a public route\n const isPublic = isPublicRoute(path, publicRoutes);\n\n // Create cookie adapter\n const adapter = new AstroCookieAdapter(context.cookies);\n\n // Check authentication status\n const result = await checkAuth(auth, adapter, cookies, autoRefresh);\n\n // If tokens were refreshed, update cookies\n if (result.newTokens) {\n coreSetAuthCookies(adapter, result.newTokens, cookies);\n }\n\n // Set auth context in locals\n context.locals.auth = result.context;\n\n // If authenticated or public route, continue\n if (result.context.isAuthenticated || isPublic) {\n return next();\n }\n\n // Not authenticated and not public - redirect or return 401\n if (loginRedirect) {\n // Add return URL as query param for redirect after login\n const returnUrl = encodeURIComponent(context.url.pathname + context.url.search);\n const redirectUrl = `${loginRedirect}?returnUrl=${returnUrl}`;\n return context.redirect(redirectUrl, 302);\n }\n\n // Return 401 Unauthorized\n return new Response(JSON.stringify({ error: 'Unauthorized' }), {\n status: 401,\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n };\n}\n\n/**\n * Set authentication cookies after login.\n *\n * Call this after a successful login to store tokens in cookies.\n *\n * @param context - Astro API context (from Astro global or API route)\n * @param tokens - Token response from login/verify/OAuth callback\n * @param cookieOptions - Optional cookie configuration overrides\n *\n * @example\n * ```typescript\n * // src/pages/api/login.ts\n * import { setAstroAuthCookies } from '@ovixa/auth-client/astro';\n * import { auth } from '../../lib/auth';\n *\n * export async function POST({ request, cookies }: APIContext) {\n * const { email, password } = await request.json();\n * const tokens = await auth.login({ email, password });\n *\n * setAstroAuthCookies({ cookies }, tokens);\n *\n * return new Response(JSON.stringify({ success: true }));\n * }\n * ```\n */\nexport function setAstroAuthCookies(\n context: Pick<AstroAPIContext, 'cookies'>,\n tokens: TokenResponse,\n cookieOptions?: CookieOptions\n): void {\n const adapter = new AstroCookieAdapter(context.cookies);\n coreSetAuthCookies(adapter, tokens, cookieOptions);\n}\n\n/**\n * Clear authentication cookies on logout.\n *\n * Call this to log out the user by removing their session cookies.\n *\n * @param context - Astro API context\n * @param cookieOptions - Optional cookie configuration overrides\n *\n * @example\n * ```typescript\n * // src/pages/api/logout.ts\n * import { clearAstroAuthCookies } from '@ovixa/auth-client/astro';\n * import { auth } from '../../lib/auth';\n *\n * export async function POST({ cookies, locals }: APIContext) {\n * // Revoke refresh token on server\n * if (locals.auth?.session?.refreshToken) {\n * await auth.logout(locals.auth.session.refreshToken);\n * }\n *\n * // Clear cookies\n * clearAstroAuthCookies({ cookies });\n *\n * return new Response(JSON.stringify({ success: true }));\n * }\n * ```\n */\nexport function clearAstroAuthCookies(\n context: Pick<AstroAPIContext, 'cookies'>,\n cookieOptions?: CookieOptions\n): void {\n const adapter = new AstroCookieAdapter(context.cookies);\n coreClearAuthCookies(adapter, cookieOptions);\n}\n\n// Re-export types for convenience\nexport type { AuthMiddlewareConfig, AuthContext, CookieOptions } from './types.js';\n"],"mappings":";;;;;;;;;AAsFA,IAAM,qBAAN,MAAkD;AAAA,EAChD,YAAoB,SAAuB;AAAvB;AAAA,EAAwB;AAAA,EAE5C,UAAU,MAAkC;AAC1C,WAAO,KAAK,QAAQ,IAAI,IAAI,GAAG;AAAA,EACjC;AAAA,EAEA,UAAU,MAAc,OAAe,SAAiC;AACtE,SAAK,QAAQ,IAAI,MAAM,OAAO;AAAA,MAC5B,MAAM,QAAQ;AAAA,MACd,QAAQ,QAAQ;AAAA,MAChB,UAAU,QAAQ;AAAA,MAClB,UAAU,QAAQ;AAAA,MAClB,QAAQ,QAAQ;AAAA,MAChB,QAAQ,QAAQ;AAAA,MAChB,SAAS,QAAQ;AAAA,IACnB,CAAC;AAAA,EACH;AAAA,EAEA,aAAa,MAAc,SAAoC;AAC7D,SAAK,QAAQ,OAAO,MAAM;AAAA,MACxB,MAAM,QAAQ;AAAA,MACd,QAAQ,QAAQ;AAAA,IAClB,CAAC;AAAA,EACH;AACF;AAoCO,SAAS,gBAAgB,QAAsD;AACpF,QAAM,EAAE,MAAM,SAAS,eAAe,CAAC,GAAG,eAAe,cAAc,KAAK,IAAI;AAEhF,SAAO,OAAO,SAA0B,SAAqD;AAC3F,UAAM,OAAO,QAAQ,IAAI;AAGzB,UAAM,WAAW,cAAc,MAAM,YAAY;AAGjD,UAAM,UAAU,IAAI,mBAAmB,QAAQ,OAAO;AAGtD,UAAM,SAAS,MAAM,UAAU,MAAM,SAAS,SAAS,WAAW;AAGlE,QAAI,OAAO,WAAW;AACpB,qBAAmB,SAAS,OAAO,WAAW,OAAO;AAAA,IACvD;AAGA,YAAQ,OAAO,OAAO,OAAO;AAG7B,QAAI,OAAO,QAAQ,mBAAmB,UAAU;AAC9C,aAAO,KAAK;AAAA,IACd;AAGA,QAAI,eAAe;AAEjB,YAAM,YAAY,mBAAmB,QAAQ,IAAI,WAAW,QAAQ,IAAI,MAAM;AAC9E,YAAM,cAAc,GAAG,aAAa,cAAc,SAAS;AAC3D,aAAO,QAAQ,SAAS,aAAa,GAAG;AAAA,IAC1C;AAGA,WAAO,IAAI,SAAS,KAAK,UAAU,EAAE,OAAO,eAAe,CAAC,GAAG;AAAA,MAC7D,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,IACF,CAAC;AAAA,EACH;AACF;AA2BO,SAAS,oBACd,SACA,QACA,eACM;AACN,QAAM,UAAU,IAAI,mBAAmB,QAAQ,OAAO;AACtD,iBAAmB,SAAS,QAAQ,aAAa;AACnD;AA6BO,SAAS,sBACd,SACA,eACM;AACN,QAAM,UAAU,IAAI,mBAAmB,QAAQ,OAAO;AACtD,mBAAqB,SAAS,aAAa;AAC7C;","names":[]}
@@ -0,0 +1,197 @@
1
+ import { TokenResponse } from '../index.js';
2
+ import { A as AuthMiddlewareConfig, a as AuthContext, C as CookieOptions } from '../types-Czfah64-.js';
3
+ import 'jose';
4
+
5
+ /**
6
+ * Express middleware for @ovixa/auth-client
7
+ *
8
+ * Provides authentication middleware for Express applications using cookie-based sessions.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import express from 'express';
13
+ * import cookieParser from 'cookie-parser';
14
+ * import { createExpressAuth, requireAuth } from '@ovixa/auth-client/express';
15
+ * import { auth } from './lib/auth';
16
+ *
17
+ * const app = express();
18
+ * app.use(cookieParser());
19
+ * app.use(createExpressAuth({
20
+ * auth,
21
+ * publicRoutes: ['/', '/login', '/signup', '/api/public/*'],
22
+ * loginRedirect: '/login',
23
+ * }));
24
+ *
25
+ * // Protected routes
26
+ * app.get('/api/me', requireAuth(), (req, res) => {
27
+ * res.json({ user: req.auth.user });
28
+ * });
29
+ * ```
30
+ */
31
+
32
+ /**
33
+ * Express Request type (minimal subset we need).
34
+ * We use this instead of importing from 'express' to avoid requiring it as a dependency.
35
+ */
36
+ interface ExpressRequest {
37
+ path: string;
38
+ url: string;
39
+ originalUrl: string;
40
+ cookies: Record<string, string>;
41
+ auth?: AuthContext;
42
+ }
43
+ /**
44
+ * Express Response type (minimal subset we need).
45
+ */
46
+ interface ExpressResponse {
47
+ cookie(name: string, value: string, options?: ExpressCookieOptions): this;
48
+ clearCookie(name: string, options?: ExpressClearCookieOptions): this;
49
+ redirect(url: string): void;
50
+ redirect(status: number, url: string): void;
51
+ status(code: number): this;
52
+ json(body: unknown): this;
53
+ }
54
+ interface ExpressCookieOptions {
55
+ path?: string;
56
+ secure?: boolean;
57
+ httpOnly?: boolean;
58
+ sameSite?: 'strict' | 'lax' | 'none' | boolean;
59
+ domain?: string;
60
+ maxAge?: number;
61
+ expires?: Date;
62
+ }
63
+ interface ExpressClearCookieOptions {
64
+ path?: string;
65
+ domain?: string;
66
+ }
67
+ /**
68
+ * Express next function.
69
+ */
70
+ type ExpressNextFunction = (err?: unknown) => void;
71
+ /**
72
+ * Express middleware handler type.
73
+ */
74
+ type ExpressMiddleware = (req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => void | Promise<void>;
75
+ /**
76
+ * Create Express authentication middleware.
77
+ *
78
+ * This middleware:
79
+ * - Checks authentication status from cookies on each request
80
+ * - Automatically refreshes expired access tokens using refresh tokens
81
+ * - Sets `req.auth` with the authentication context
82
+ * - Optionally redirects unauthenticated requests to a login page
83
+ * - Allows public routes to bypass authentication
84
+ *
85
+ * **Note:** Requires `cookie-parser` middleware to be installed and used before this middleware.
86
+ *
87
+ * @param config - Middleware configuration
88
+ * @returns Express middleware
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * import express from 'express';
93
+ * import cookieParser from 'cookie-parser';
94
+ * import { createExpressAuth } from '@ovixa/auth-client/express';
95
+ * import { OvixaAuth } from '@ovixa/auth-client';
96
+ *
97
+ * const auth = new OvixaAuth({
98
+ * authUrl: process.env.AUTH_URL!,
99
+ * realmId: process.env.AUTH_REALM_ID!,
100
+ * });
101
+ *
102
+ * const app = express();
103
+ * app.use(cookieParser());
104
+ * app.use(createExpressAuth({
105
+ * auth,
106
+ * publicRoutes: ['/', '/login', '/signup'],
107
+ * loginRedirect: '/login',
108
+ * cookies: {
109
+ * secure: process.env.NODE_ENV === 'production',
110
+ * },
111
+ * }));
112
+ * ```
113
+ */
114
+ declare function createExpressAuth(config: AuthMiddlewareConfig): ExpressMiddleware;
115
+ /**
116
+ * Express middleware to require authentication on specific routes.
117
+ *
118
+ * Use this as an additional guard on routes that must be authenticated,
119
+ * even when the main middleware is configured with `loginRedirect`.
120
+ *
121
+ * @param options - Optional configuration
122
+ * @returns Express middleware
123
+ *
124
+ * @example
125
+ * ```typescript
126
+ * import { requireAuth } from '@ovixa/auth-client/express';
127
+ *
128
+ * // API route that requires authentication (returns 401 if not authenticated)
129
+ * app.get('/api/me', requireAuth(), (req, res) => {
130
+ * res.json({ user: req.auth.user });
131
+ * });
132
+ *
133
+ * // API route with custom redirect
134
+ * app.get('/dashboard', requireAuth({ redirect: '/login' }), (req, res) => {
135
+ * res.render('dashboard', { user: req.auth.user });
136
+ * });
137
+ * ```
138
+ */
139
+ declare function requireAuth(options?: {
140
+ redirect?: string;
141
+ }): ExpressMiddleware;
142
+ /**
143
+ * Set authentication cookies after login.
144
+ *
145
+ * Call this after a successful login to store tokens in cookies.
146
+ *
147
+ * @param res - Express response object
148
+ * @param req - Express request object (for adapter consistency)
149
+ * @param tokens - Token response from login/verify/OAuth callback
150
+ * @param cookieOptions - Optional cookie configuration overrides
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * import { setExpressAuthCookies } from '@ovixa/auth-client/express';
155
+ * import { auth } from './lib/auth';
156
+ *
157
+ * app.post('/api/login', async (req, res) => {
158
+ * const { email, password } = req.body;
159
+ * const tokens = await auth.login({ email, password });
160
+ *
161
+ * setExpressAuthCookies(res, req, tokens);
162
+ *
163
+ * res.json({ success: true });
164
+ * });
165
+ * ```
166
+ */
167
+ declare function setExpressAuthCookies(res: ExpressResponse, req: ExpressRequest, tokens: TokenResponse, cookieOptions?: CookieOptions): void;
168
+ /**
169
+ * Clear authentication cookies on logout.
170
+ *
171
+ * Call this to log out the user by removing their session cookies.
172
+ *
173
+ * @param res - Express response object
174
+ * @param req - Express request object (for adapter consistency)
175
+ * @param cookieOptions - Optional cookie configuration overrides
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * import { clearExpressAuthCookies } from '@ovixa/auth-client/express';
180
+ * import { auth } from './lib/auth';
181
+ *
182
+ * app.post('/api/logout', async (req, res) => {
183
+ * // Revoke refresh token on server
184
+ * if (req.auth?.session?.refreshToken) {
185
+ * await auth.logout(req.auth.session.refreshToken);
186
+ * }
187
+ *
188
+ * // Clear cookies
189
+ * clearExpressAuthCookies(res, req);
190
+ *
191
+ * res.json({ success: true });
192
+ * });
193
+ * ```
194
+ */
195
+ declare function clearExpressAuthCookies(res: ExpressResponse, req: ExpressRequest, cookieOptions?: CookieOptions): void;
196
+
197
+ export { AuthContext, AuthMiddlewareConfig, CookieOptions, clearExpressAuthCookies, createExpressAuth, requireAuth, setExpressAuthCookies };
@@ -0,0 +1,87 @@
1
+ import {
2
+ checkAuth,
3
+ clearAuthCookies,
4
+ isPublicRoute,
5
+ setAuthCookies
6
+ } from "../chunk-Y5NJCTZO.js";
7
+ import "../chunk-UHRF6AFJ.js";
8
+
9
+ // src/middleware/express.ts
10
+ var ExpressCookieAdapter = class {
11
+ constructor(req, res) {
12
+ this.req = req;
13
+ this.res = res;
14
+ }
15
+ getCookie(name) {
16
+ return this.req.cookies[name];
17
+ }
18
+ setCookie(name, value, options) {
19
+ this.res.cookie(name, value, {
20
+ path: options.path,
21
+ secure: options.secure,
22
+ httpOnly: options.httpOnly,
23
+ sameSite: options.sameSite,
24
+ domain: options.domain,
25
+ maxAge: options.maxAge ? options.maxAge * 1e3 : void 0,
26
+ // Express uses milliseconds
27
+ expires: options.expires
28
+ });
29
+ }
30
+ deleteCookie(name, options) {
31
+ this.res.clearCookie(name, {
32
+ path: options.path,
33
+ domain: options.domain
34
+ });
35
+ }
36
+ };
37
+ function createExpressAuth(config) {
38
+ const { auth, cookies, publicRoutes = [], loginRedirect, autoRefresh = true } = config;
39
+ return async (req, res, next) => {
40
+ const path = req.path;
41
+ const isPublic = isPublicRoute(path, publicRoutes);
42
+ const adapter = new ExpressCookieAdapter(req, res);
43
+ const result = await checkAuth(auth, adapter, cookies, autoRefresh);
44
+ if (result.newTokens) {
45
+ setAuthCookies(adapter, result.newTokens, cookies);
46
+ }
47
+ req.auth = result.context;
48
+ if (result.context.isAuthenticated || isPublic) {
49
+ return next();
50
+ }
51
+ if (loginRedirect) {
52
+ const returnUrl = encodeURIComponent(req.originalUrl);
53
+ const redirectUrl = `${loginRedirect}?returnUrl=${returnUrl}`;
54
+ res.redirect(302, redirectUrl);
55
+ return;
56
+ }
57
+ res.status(401).json({ error: "Unauthorized" });
58
+ };
59
+ }
60
+ function requireAuth(options) {
61
+ return (req, res, next) => {
62
+ if (req.auth?.isAuthenticated) {
63
+ return next();
64
+ }
65
+ if (options?.redirect) {
66
+ const returnUrl = encodeURIComponent(req.originalUrl);
67
+ res.redirect(302, `${options.redirect}?returnUrl=${returnUrl}`);
68
+ return;
69
+ }
70
+ res.status(401).json({ error: "Unauthorized" });
71
+ };
72
+ }
73
+ function setExpressAuthCookies(res, req, tokens, cookieOptions) {
74
+ const adapter = new ExpressCookieAdapter(req, res);
75
+ setAuthCookies(adapter, tokens, cookieOptions);
76
+ }
77
+ function clearExpressAuthCookies(res, req, cookieOptions) {
78
+ const adapter = new ExpressCookieAdapter(req, res);
79
+ clearAuthCookies(adapter, cookieOptions);
80
+ }
81
+ export {
82
+ clearExpressAuthCookies,
83
+ createExpressAuth,
84
+ requireAuth,
85
+ setExpressAuthCookies
86
+ };
87
+ //# sourceMappingURL=express.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/middleware/express.ts"],"sourcesContent":["/**\n * Express middleware for @ovixa/auth-client\n *\n * Provides authentication middleware for Express applications using cookie-based sessions.\n *\n * @example\n * ```typescript\n * import express from 'express';\n * import cookieParser from 'cookie-parser';\n * import { createExpressAuth, requireAuth } from '@ovixa/auth-client/express';\n * import { auth } from './lib/auth';\n *\n * const app = express();\n * app.use(cookieParser());\n * app.use(createExpressAuth({\n * auth,\n * publicRoutes: ['/', '/login', '/signup', '/api/public/*'],\n * loginRedirect: '/login',\n * }));\n *\n * // Protected routes\n * app.get('/api/me', requireAuth(), (req, res) => {\n * res.json({ user: req.auth.user });\n * });\n * ```\n */\n\nimport type { TokenResponse } from '../index.js';\nimport type {\n AuthMiddlewareConfig,\n AuthContext,\n CookieAdapter,\n SetCookieOptions,\n DeleteCookieOptions,\n CookieOptions,\n} from './types.js';\nimport { isPublicRoute } from './types.js';\nimport {\n checkAuth,\n setAuthCookies as coreSetAuthCookies,\n clearAuthCookies as coreClearAuthCookies,\n} from './core.js';\n\n/**\n * Express Request type (minimal subset we need).\n * We use this instead of importing from 'express' to avoid requiring it as a dependency.\n */\ninterface ExpressRequest {\n path: string;\n url: string;\n originalUrl: string;\n cookies: Record<string, string>;\n auth?: AuthContext;\n}\n\n/**\n * Express Response type (minimal subset we need).\n */\ninterface ExpressResponse {\n cookie(name: string, value: string, options?: ExpressCookieOptions): this;\n clearCookie(name: string, options?: ExpressClearCookieOptions): this;\n redirect(url: string): void;\n redirect(status: number, url: string): void;\n status(code: number): this;\n json(body: unknown): this;\n}\n\ninterface ExpressCookieOptions {\n path?: string;\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: 'strict' | 'lax' | 'none' | boolean;\n domain?: string;\n maxAge?: number;\n expires?: Date;\n}\n\ninterface ExpressClearCookieOptions {\n path?: string;\n domain?: string;\n}\n\n/**\n * Express next function.\n */\ntype ExpressNextFunction = (err?: unknown) => void;\n\n/**\n * Express middleware handler type.\n */\ntype ExpressMiddleware = (\n req: ExpressRequest,\n res: ExpressResponse,\n next: ExpressNextFunction\n) => void | Promise<void>;\n\n/**\n * Cookie adapter for Express's cookie API.\n *\n * Requires `cookie-parser` middleware to be installed and used before this middleware.\n */\nclass ExpressCookieAdapter implements CookieAdapter {\n constructor(\n private req: ExpressRequest,\n private res: ExpressResponse\n ) {}\n\n getCookie(name: string): string | undefined {\n return this.req.cookies[name];\n }\n\n setCookie(name: string, value: string, options: SetCookieOptions): void {\n this.res.cookie(name, value, {\n path: options.path,\n secure: options.secure,\n httpOnly: options.httpOnly,\n sameSite: options.sameSite,\n domain: options.domain,\n maxAge: options.maxAge ? options.maxAge * 1000 : undefined, // Express uses milliseconds\n expires: options.expires,\n });\n }\n\n deleteCookie(name: string, options: DeleteCookieOptions): void {\n this.res.clearCookie(name, {\n path: options.path,\n domain: options.domain,\n });\n }\n}\n\n/**\n * Create Express authentication middleware.\n *\n * This middleware:\n * - Checks authentication status from cookies on each request\n * - Automatically refreshes expired access tokens using refresh tokens\n * - Sets `req.auth` with the authentication context\n * - Optionally redirects unauthenticated requests to a login page\n * - Allows public routes to bypass authentication\n *\n * **Note:** Requires `cookie-parser` middleware to be installed and used before this middleware.\n *\n * @param config - Middleware configuration\n * @returns Express middleware\n *\n * @example\n * ```typescript\n * import express from 'express';\n * import cookieParser from 'cookie-parser';\n * import { createExpressAuth } from '@ovixa/auth-client/express';\n * import { OvixaAuth } from '@ovixa/auth-client';\n *\n * const auth = new OvixaAuth({\n * authUrl: process.env.AUTH_URL!,\n * realmId: process.env.AUTH_REALM_ID!,\n * });\n *\n * const app = express();\n * app.use(cookieParser());\n * app.use(createExpressAuth({\n * auth,\n * publicRoutes: ['/', '/login', '/signup'],\n * loginRedirect: '/login',\n * cookies: {\n * secure: process.env.NODE_ENV === 'production',\n * },\n * }));\n * ```\n */\nexport function createExpressAuth(config: AuthMiddlewareConfig): ExpressMiddleware {\n const { auth, cookies, publicRoutes = [], loginRedirect, autoRefresh = true } = config;\n\n return async (\n req: ExpressRequest,\n res: ExpressResponse,\n next: ExpressNextFunction\n ): Promise<void> => {\n const path = req.path;\n\n // Check if this is a public route\n const isPublic = isPublicRoute(path, publicRoutes);\n\n // Create cookie adapter\n const adapter = new ExpressCookieAdapter(req, res);\n\n // Check authentication status\n const result = await checkAuth(auth, adapter, cookies, autoRefresh);\n\n // If tokens were refreshed, update cookies\n if (result.newTokens) {\n coreSetAuthCookies(adapter, result.newTokens, cookies);\n }\n\n // Set auth context on request\n req.auth = result.context;\n\n // If authenticated or public route, continue\n if (result.context.isAuthenticated || isPublic) {\n return next();\n }\n\n // Not authenticated and not public - redirect or return 401\n if (loginRedirect) {\n // Add return URL as query param for redirect after login\n const returnUrl = encodeURIComponent(req.originalUrl);\n const redirectUrl = `${loginRedirect}?returnUrl=${returnUrl}`;\n res.redirect(302, redirectUrl);\n return;\n }\n\n // Return 401 Unauthorized\n res.status(401).json({ error: 'Unauthorized' });\n };\n}\n\n/**\n * Express middleware to require authentication on specific routes.\n *\n * Use this as an additional guard on routes that must be authenticated,\n * even when the main middleware is configured with `loginRedirect`.\n *\n * @param options - Optional configuration\n * @returns Express middleware\n *\n * @example\n * ```typescript\n * import { requireAuth } from '@ovixa/auth-client/express';\n *\n * // API route that requires authentication (returns 401 if not authenticated)\n * app.get('/api/me', requireAuth(), (req, res) => {\n * res.json({ user: req.auth.user });\n * });\n *\n * // API route with custom redirect\n * app.get('/dashboard', requireAuth({ redirect: '/login' }), (req, res) => {\n * res.render('dashboard', { user: req.auth.user });\n * });\n * ```\n */\nexport function requireAuth(options?: { redirect?: string }): ExpressMiddleware {\n return (req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction): void => {\n if (req.auth?.isAuthenticated) {\n return next();\n }\n\n if (options?.redirect) {\n const returnUrl = encodeURIComponent(req.originalUrl);\n res.redirect(302, `${options.redirect}?returnUrl=${returnUrl}`);\n return;\n }\n\n res.status(401).json({ error: 'Unauthorized' });\n };\n}\n\n/**\n * Set authentication cookies after login.\n *\n * Call this after a successful login to store tokens in cookies.\n *\n * @param res - Express response object\n * @param req - Express request object (for adapter consistency)\n * @param tokens - Token response from login/verify/OAuth callback\n * @param cookieOptions - Optional cookie configuration overrides\n *\n * @example\n * ```typescript\n * import { setExpressAuthCookies } from '@ovixa/auth-client/express';\n * import { auth } from './lib/auth';\n *\n * app.post('/api/login', async (req, res) => {\n * const { email, password } = req.body;\n * const tokens = await auth.login({ email, password });\n *\n * setExpressAuthCookies(res, req, tokens);\n *\n * res.json({ success: true });\n * });\n * ```\n */\nexport function setExpressAuthCookies(\n res: ExpressResponse,\n req: ExpressRequest,\n tokens: TokenResponse,\n cookieOptions?: CookieOptions\n): void {\n const adapter = new ExpressCookieAdapter(req, res);\n coreSetAuthCookies(adapter, tokens, cookieOptions);\n}\n\n/**\n * Clear authentication cookies on logout.\n *\n * Call this to log out the user by removing their session cookies.\n *\n * @param res - Express response object\n * @param req - Express request object (for adapter consistency)\n * @param cookieOptions - Optional cookie configuration overrides\n *\n * @example\n * ```typescript\n * import { clearExpressAuthCookies } from '@ovixa/auth-client/express';\n * import { auth } from './lib/auth';\n *\n * app.post('/api/logout', async (req, res) => {\n * // Revoke refresh token on server\n * if (req.auth?.session?.refreshToken) {\n * await auth.logout(req.auth.session.refreshToken);\n * }\n *\n * // Clear cookies\n * clearExpressAuthCookies(res, req);\n *\n * res.json({ success: true });\n * });\n * ```\n */\nexport function clearExpressAuthCookies(\n res: ExpressResponse,\n req: ExpressRequest,\n cookieOptions?: CookieOptions\n): void {\n const adapter = new ExpressCookieAdapter(req, res);\n coreClearAuthCookies(adapter, cookieOptions);\n}\n\n// Re-export types for convenience\nexport type { AuthMiddlewareConfig, AuthContext, CookieOptions } from './types.js';\n"],"mappings":";;;;;;;;;AAqGA,IAAM,uBAAN,MAAoD;AAAA,EAClD,YACU,KACA,KACR;AAFQ;AACA;AAAA,EACP;AAAA,EAEH,UAAU,MAAkC;AAC1C,WAAO,KAAK,IAAI,QAAQ,IAAI;AAAA,EAC9B;AAAA,EAEA,UAAU,MAAc,OAAe,SAAiC;AACtE,SAAK,IAAI,OAAO,MAAM,OAAO;AAAA,MAC3B,MAAM,QAAQ;AAAA,MACd,QAAQ,QAAQ;AAAA,MAChB,UAAU,QAAQ;AAAA,MAClB,UAAU,QAAQ;AAAA,MAClB,QAAQ,QAAQ;AAAA,MAChB,QAAQ,QAAQ,SAAS,QAAQ,SAAS,MAAO;AAAA;AAAA,MACjD,SAAS,QAAQ;AAAA,IACnB,CAAC;AAAA,EACH;AAAA,EAEA,aAAa,MAAc,SAAoC;AAC7D,SAAK,IAAI,YAAY,MAAM;AAAA,MACzB,MAAM,QAAQ;AAAA,MACd,QAAQ,QAAQ;AAAA,IAClB,CAAC;AAAA,EACH;AACF;AAyCO,SAAS,kBAAkB,QAAiD;AACjF,QAAM,EAAE,MAAM,SAAS,eAAe,CAAC,GAAG,eAAe,cAAc,KAAK,IAAI;AAEhF,SAAO,OACL,KACA,KACA,SACkB;AAClB,UAAM,OAAO,IAAI;AAGjB,UAAM,WAAW,cAAc,MAAM,YAAY;AAGjD,UAAM,UAAU,IAAI,qBAAqB,KAAK,GAAG;AAGjD,UAAM,SAAS,MAAM,UAAU,MAAM,SAAS,SAAS,WAAW;AAGlE,QAAI,OAAO,WAAW;AACpB,qBAAmB,SAAS,OAAO,WAAW,OAAO;AAAA,IACvD;AAGA,QAAI,OAAO,OAAO;AAGlB,QAAI,OAAO,QAAQ,mBAAmB,UAAU;AAC9C,aAAO,KAAK;AAAA,IACd;AAGA,QAAI,eAAe;AAEjB,YAAM,YAAY,mBAAmB,IAAI,WAAW;AACpD,YAAM,cAAc,GAAG,aAAa,cAAc,SAAS;AAC3D,UAAI,SAAS,KAAK,WAAW;AAC7B;AAAA,IACF;AAGA,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,EAChD;AACF;AA0BO,SAAS,YAAY,SAAoD;AAC9E,SAAO,CAAC,KAAqB,KAAsB,SAAoC;AACrF,QAAI,IAAI,MAAM,iBAAiB;AAC7B,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,SAAS,UAAU;AACrB,YAAM,YAAY,mBAAmB,IAAI,WAAW;AACpD,UAAI,SAAS,KAAK,GAAG,QAAQ,QAAQ,cAAc,SAAS,EAAE;AAC9D;AAAA,IACF;AAEA,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,EAChD;AACF;AA2BO,SAAS,sBACd,KACA,KACA,QACA,eACM;AACN,QAAM,UAAU,IAAI,qBAAqB,KAAK,GAAG;AACjD,iBAAmB,SAAS,QAAQ,aAAa;AACnD;AA6BO,SAAS,wBACd,KACA,KACA,eACM;AACN,QAAM,UAAU,IAAI,qBAAqB,KAAK,GAAG;AACjD,mBAAqB,SAAS,aAAa;AAC7C;","names":[]}
@@ -0,0 +1,57 @@
1
+ import { OvixaAuth, User, Session } from './index.js';
2
+
3
+ /**
4
+ * Middleware types for @ovixa/auth-client
5
+ *
6
+ * Provides generic adapter interfaces and shared types for framework integrations.
7
+ */
8
+
9
+ /**
10
+ * Cookie configuration options for auth middleware.
11
+ */
12
+ interface CookieOptions {
13
+ /** Name of the access token cookie (default: 'ovixa_access_token') */
14
+ accessTokenCookie?: string;
15
+ /** Name of the refresh token cookie (default: 'ovixa_refresh_token') */
16
+ refreshTokenCookie?: string;
17
+ /** Cookie path (default: '/') */
18
+ path?: string;
19
+ /** Whether to use secure cookies (default: true) */
20
+ secure?: boolean;
21
+ /** Whether cookies are HTTP-only (default: true) */
22
+ httpOnly?: boolean;
23
+ /** SameSite cookie policy (default: 'lax') */
24
+ sameSite?: 'strict' | 'lax' | 'none';
25
+ /** Cookie domain (optional, defaults to current domain) */
26
+ domain?: string;
27
+ /** Max age for cookies in seconds (optional, defaults to token expiry) */
28
+ maxAge?: number;
29
+ }
30
+ /**
31
+ * Configuration for auth middleware.
32
+ */
33
+ interface AuthMiddlewareConfig {
34
+ /** OvixaAuth client instance */
35
+ auth: OvixaAuth;
36
+ /** Cookie configuration options */
37
+ cookies?: CookieOptions;
38
+ /** Routes that don't require authentication */
39
+ publicRoutes?: string[];
40
+ /** URL to redirect unauthenticated requests (if not set, returns 401) */
41
+ loginRedirect?: string;
42
+ /** Whether to automatically refresh expired tokens (default: true) */
43
+ autoRefresh?: boolean;
44
+ }
45
+ /**
46
+ * Authentication context available in request handlers.
47
+ */
48
+ interface AuthContext {
49
+ /** The authenticated user, or null if not authenticated */
50
+ user: User | null;
51
+ /** The current session, or null if not authenticated */
52
+ session: Session | null;
53
+ /** Whether the request is authenticated */
54
+ isAuthenticated: boolean;
55
+ }
56
+
57
+ export type { AuthMiddlewareConfig as A, CookieOptions as C, AuthContext as a };