@mindfulauth/core 2.0.0-beta.5 → 2.0.0-beta.6

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,195 @@
1
+ ---
2
+ // Mindful Auth - Verify Magic Link Script Component
3
+ // Provides: Magic link verification with 2FA support
4
+ ---
5
+ <script is:inline>
6
+ // Verify Magic Link Script - Astro Optimized
7
+
8
+ function getPathParams() {
9
+ const pathParts = window.location.pathname.split('/');
10
+ return {
11
+ recordid: pathParts[2],
12
+ token: pathParts[3]
13
+ };
14
+ }
15
+
16
+ async function handleVerifyMagicLinkSubmit(event) {
17
+ if (event) event.preventDefault();
18
+
19
+ const form = document.querySelector('[data-mindfulauth-form="verify-magic-link"]');
20
+ if (!form) return;
21
+ const messageEl = document.querySelector('[data-mindfulauth-field="message"]');
22
+ if (!messageEl) return;
23
+ const twoFACodeEl = form.querySelector('[data-mindfulauth-field="twofa-code"]');
24
+ const submitBtn = form.querySelector('button[type="submit"]');
25
+
26
+ // Skip API call on localhost to prevent production logs pollution
27
+ const hostname = window.location.hostname;
28
+ if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname.endsWith('.local')) {
29
+ messageEl.textContent = 'Magic link verification skipped on localhost.';
30
+ console.log('[Verify Magic Link] Skipping API call on localhost');
31
+ if (form) form.style.display = 'none';
32
+ return;
33
+ }
34
+
35
+ const { recordid, token } = getPathParams();
36
+
37
+ if (!recordid || !token) {
38
+ messageEl.textContent = "Invalid or expired magic link. Please request a new one.";
39
+ if (form) form.style.display = 'none';
40
+ return;
41
+ }
42
+
43
+ // Get Turnstile token
44
+ const turnstileToken = form.querySelector('[name="cf-turnstile-response"]')?.value;
45
+ if (!turnstileToken) {
46
+ messageEl.textContent = "Bot protection validation required.";
47
+ if (submitBtn) submitBtn.disabled = true;
48
+ return;
49
+ }
50
+
51
+ messageEl.textContent = "Verifying magic link...";
52
+ if (submitBtn) submitBtn.disabled = true;
53
+
54
+ try {
55
+ const requestBody = {
56
+ 'cf-turnstile-response': turnstileToken
57
+ };
58
+
59
+ // Include 2FA code if provided
60
+ if (twoFACodeEl && twoFACodeEl.value) {
61
+ requestBody.twoFACode = twoFACodeEl.value;
62
+ }
63
+
64
+ const endpoint = `/auth/verify-magic-link/${recordid}/${token}`;
65
+ console.log('[Verify Magic Link] Making request to:', endpoint);
66
+ console.log('[Verify Magic Link] Request body:', requestBody);
67
+
68
+ const response = await window.apiFetch(endpoint, {
69
+ body: JSON.stringify(requestBody)
70
+ });
71
+
72
+ console.log('[Verify Magic Link] Response status:', response.status);
73
+ const result = await response.json();
74
+ console.log('[Verify Magic Link] Response body:', result);
75
+
76
+ // Check if 2FA is required
77
+ if (result.requires2FA) {
78
+ // Reset Turnstile to generate a fresh token for the 2FA submission
79
+ // (Turnstile tokens are single-use; first request consumed it)
80
+ window.turnstile?.reset();
81
+
82
+ // Show the 2FA input field
83
+ const twoFAContainer = form.querySelector('[data-mindfulauth-field="twofa-code-container"]');
84
+ if (twoFAContainer) {
85
+ twoFAContainer.removeAttribute('hidden');
86
+ twoFAContainer.classList && twoFAContainer.classList.remove('hidden');
87
+ twoFAContainer.style.setProperty('display', 'block', 'important');
88
+ // Try common display values
89
+ if (window.getComputedStyle(twoFAContainer).display === 'none') {
90
+ twoFAContainer.style.setProperty('display', 'flex', 'important');
91
+ }
92
+ }
93
+ if (twoFACodeEl) {
94
+ twoFACodeEl.focus();
95
+ }
96
+ messageEl.textContent = '2FA code is required to complete login.';
97
+ if (submitBtn) {
98
+ submitBtn.textContent = 'Verify 2FA Code';
99
+ submitBtn.disabled = false;
100
+ }
101
+ return;
102
+ }
103
+
104
+ if (result.success) {
105
+ console.log('[Verify Magic Link] Verification successful');
106
+ messageEl.textContent = result.message || 'Login successful! Redirecting...';
107
+ if (form) form.style.display = 'none';
108
+
109
+ // Redirect to secure area (match login.js pattern)
110
+ if (result.redirect) {
111
+ console.log('[Verify Magic Link] Redirecting to:', result.redirect);
112
+ setTimeout(() => {
113
+ window.location.assign(result.redirect);
114
+ }, 200);
115
+ }
116
+ } else {
117
+ console.error('[Verify Magic Link] Verification failed:', result.message);
118
+ throw new Error(result.message || 'Verification failed.');
119
+ }
120
+ } catch (error) {
121
+ console.error('[Verify Magic Link] Error:', error);
122
+ messageEl.textContent = `Error: ${error.message}`;
123
+ if (submitBtn) submitBtn.disabled = false;
124
+ window.turnstile?.reset();
125
+ }
126
+ }
127
+
128
+ // --- MAIN EXECUTION ---
129
+ document.addEventListener('DOMContentLoaded', function() {
130
+ const form = document.querySelector('[data-mindfulauth-form="verify-magic-link"]');
131
+ if (!form) return;
132
+
133
+ // Initialize message and disable button until Turnstile is ready
134
+ const messageEl = document.querySelector('[data-mindfulauth-field="message"]');
135
+ const submitBtn = form.querySelector('button[type="submit"]');
136
+ if (messageEl) {
137
+ messageEl.textContent = 'Loading bot protection...';
138
+ }
139
+ if (submitBtn) {
140
+ submitBtn.disabled = true;
141
+ }
142
+
143
+ // Initially hide 2FA field - it will be shown if needed
144
+ const twoFAContainer = form.querySelector('[data-mindfulauth-field="twofa-code-container"]');
145
+ if (twoFAContainer) {
146
+ twoFAContainer.style.display = 'none';
147
+ }
148
+
149
+ // Wait for Turnstile to be ready
150
+ let turnstileReady = false;
151
+ const checkTurnstile = setInterval(() => {
152
+ const turnstileToken = form.querySelector('[name="cf-turnstile-response"]')?.value;
153
+ if (turnstileToken) {
154
+ console.log('[Verify Magic Link] Turnstile token loaded - ready for user verification');
155
+ clearInterval(checkTurnstile);
156
+ turnstileReady = true;
157
+ const messageEl = document.querySelector('[data-mindfulauth-field="message"]');
158
+ if (messageEl) {
159
+ messageEl.textContent = 'Ready to verify. Click the button below to sign in.';
160
+ }
161
+ const submitBtn = form.querySelector('button[type="submit"]');
162
+ if (submitBtn) {
163
+ submitBtn.disabled = false;
164
+ }
165
+ }
166
+ }, 100);
167
+
168
+ // Check for Turnstile load every 500ms for up to 30 seconds
169
+ // (don't show error proactively - only if user tries to submit)
170
+ let turnstileCheckCount = 0;
171
+ const extendedCheckTurnstile = setInterval(() => {
172
+ const turnstileToken = form.querySelector('[name="cf-turnstile-response"]')?.value;
173
+ if (turnstileToken && !turnstileReady) {
174
+ clearInterval(extendedCheckTurnstile);
175
+ turnstileReady = true;
176
+ const messageEl = document.querySelector('[data-mindfulauth-field="message"]');
177
+ if (messageEl) {
178
+ messageEl.textContent = 'Ready to verify. Click the button below to sign in.';
179
+ }
180
+ const submitBtn = form.querySelector('button[type="submit"]');
181
+ if (submitBtn) {
182
+ submitBtn.disabled = false;
183
+ }
184
+ }
185
+ turnstileCheckCount++;
186
+ // Stop checking after 30 seconds
187
+ if (turnstileCheckCount > 60) {
188
+ clearInterval(extendedCheckTurnstile);
189
+ }
190
+ }, 500);
191
+
192
+ // Also handle explicit form submission (for 2FA code entry)
193
+ form.addEventListener('submit', handleVerifyMagicLinkSubmit);
194
+ });
195
+ </script>
package/package.json CHANGED
@@ -1,26 +1,31 @@
1
1
  {
2
2
  "name": "@mindfulauth/core",
3
- "version": "2.0.0-beta.5",
3
+ "version": "2.0.0-beta.6",
4
4
  "description": "Mindful Auth core authentication library for Astro 6",
5
5
  "type": "module",
6
- "main": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
6
+ "main": "./dist/core/index.js",
7
+ "types": "./dist/core/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
10
+ "types": "./dist/core/index.d.ts",
11
+ "import": "./dist/core/index.js"
12
12
  },
13
+ "./astro": {
14
+ "types": "./dist/astro/index.d.ts",
15
+ "import": "./dist/astro/index.js"
16
+ },
17
+ "./astro/*.astro": "./dist/astro/*.astro",
13
18
  "./middleware": {
14
- "types": "./dist/middleware.d.ts",
15
- "import": "./dist/middleware.js"
19
+ "types": "./dist/core/middleware.d.ts",
20
+ "import": "./dist/core/middleware.js"
16
21
  },
17
22
  "./auth-handler": {
18
- "types": "./dist/auth-handler.d.ts",
19
- "import": "./dist/auth-handler.js"
23
+ "types": "./dist/core/auth-handler.d.ts",
24
+ "import": "./dist/core/auth-handler.js"
20
25
  },
21
26
  "./config": {
22
- "types": "./dist/config.d.ts",
23
- "import": "./dist/config.js"
27
+ "types": "./dist/core/config.d.ts",
28
+ "import": "./dist/core/config.js"
24
29
  }
25
30
  },
26
31
  "files": [
@@ -28,7 +33,7 @@
28
33
  "README.md"
29
34
  ],
30
35
  "scripts": {
31
- "build": "tsc",
36
+ "build": "tsc && cp src/astro/*.astro dist/astro/",
32
37
  "dev": "tsc --watch",
33
38
  "prepublishOnly": "npm run build"
34
39
  },
@@ -1,5 +0,0 @@
1
- /** Handle GET requests (email verification, password reset links, etc.) */
2
- export declare function handleAuthGet(rawEndpoint: string, request: Request, url: URL, locals?: any): Promise<Response>;
3
- /** Handle POST requests (login, 2FA, password changes, etc.) */
4
- export declare function handleAuthPost(rawEndpoint: string, request: Request, url: URL, locals?: any): Promise<Response>;
5
- //# sourceMappingURL=auth-handler.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth-handler.d.ts","sourceRoot":"","sources":["../src/auth-handler.ts"],"names":[],"mappings":"AAwEA,2EAA2E;AAC3E,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6BpH;AAED,gEAAgE;AAChE,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyDrH"}
@@ -1,154 +0,0 @@
1
- // Auth proxy handler for Mindful Auth
2
- // Forwards authentication requests to the central Mindful Auth service
3
- //
4
- // ASTRO 6 MIGRATION:
5
- // - Astro v6 removed context.locals.runtime.env. Env vars now import from 'cloudflare:workers'.
6
- // - Note: @cloudflare/workers-types must be installed and referenced in env.d.ts.
7
- import { env } from 'cloudflare:workers';
8
- import { CENTRAL_AUTH_ORIGIN, ALLOWED_AUTH_METHODS, MAX_BODY_SIZE_BYTES, AUTH_PROXY_TIMEOUT_MS } from './config';
9
- import { sanitizeEndpoint } from './security';
10
- const JSON_HEADERS = { 'Content-Type': 'application/json' };
11
- const jsonError = (error, status) => new Response(JSON.stringify({ error }), { status, headers: JSON_HEADERS });
12
- /** Build proxy headers from incoming request */
13
- function buildProxyHeaders(request, tenantDomain, apiKey) {
14
- const headers = {
15
- 'Content-Type': 'application/json',
16
- 'X-Tenant-Domain': tenantDomain,
17
- 'X-Requested-With': 'XMLHttpRequest'
18
- };
19
- if (apiKey)
20
- headers['Authorization'] = `Bearer ${apiKey}`;
21
- const cookie = request.headers.get('Cookie');
22
- if (cookie)
23
- headers['Cookie'] = cookie;
24
- const clientIp = request.headers.get('cf-connecting-ip') ||
25
- request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ||
26
- request.headers.get('x-real-ip');
27
- if (clientIp)
28
- headers['X-Original-Client-IP'] = clientIp;
29
- const userAgent = request.headers.get('user-agent');
30
- if (userAgent)
31
- headers['User-Agent'] = userAgent;
32
- return headers;
33
- }
34
- /** Fetch with timeout */
35
- async function fetchWithTimeout(url, options) {
36
- const controller = new AbortController();
37
- const timeoutId = setTimeout(() => controller.abort(), AUTH_PROXY_TIMEOUT_MS);
38
- try {
39
- return await fetch(url, { ...options, signal: controller.signal });
40
- }
41
- finally {
42
- clearTimeout(timeoutId);
43
- }
44
- }
45
- /** Extract mirrored session cookie (removes Domain to use tenant domain) */
46
- function getMirroredCookie(resp) {
47
- const setCookie = resp.headers.get('set-cookie');
48
- return setCookie?.includes('session_id=')
49
- ? setCookie.replace(/Domain=[^;]+;?\s*/i, '')
50
- : null;
51
- }
52
- /** Check if redirect is safe (relative, no open redirect) */
53
- function isSafeRedirect(url) {
54
- return url.startsWith('/') && !url.startsWith('//');
55
- }
56
- /** Build response with standard headers */
57
- function buildResponse(data, status, cookie) {
58
- const headers = new Headers({
59
- 'Content-Type': 'application/json',
60
- 'Cache-Control': 'no-store, no-cache, must-revalidate, private'
61
- });
62
- if (cookie)
63
- headers.set('Set-Cookie', cookie);
64
- return new Response(JSON.stringify(data), { status, headers });
65
- }
66
- /** Handle GET requests (email verification, password reset links, etc.) */
67
- export async function handleAuthGet(rawEndpoint, request, url, locals) {
68
- // ASTRO 6 CHANGE: Environment variables accessed from 'cloudflare:workers' env directly.
69
- const internalApiKey = env.INTERNAL_API_KEY || import.meta.env.INTERNAL_API_KEY;
70
- if (!internalApiKey)
71
- console.error('[auth-handler] INTERNAL_API_KEY not configured');
72
- const endpoint = sanitizeEndpoint(rawEndpoint);
73
- if (!endpoint)
74
- return jsonError('Bad request', 400);
75
- const apiUrl = new URL(`${CENTRAL_AUTH_ORIGIN}/auth/${endpoint}`);
76
- url.searchParams.forEach((v, k) => apiUrl.searchParams.set(k, v));
77
- let resp;
78
- try {
79
- resp = await fetchWithTimeout(apiUrl.toString(), {
80
- method: 'GET',
81
- headers: buildProxyHeaders(request, url.hostname, internalApiKey)
82
- });
83
- }
84
- catch (e) {
85
- if (e.name === 'AbortError')
86
- return jsonError('Request timeout', 504);
87
- throw e;
88
- }
89
- // Handle redirect
90
- const location = resp.headers.get('Location');
91
- if (resp.status === 302 && location && isSafeRedirect(location)) {
92
- return new Response(null, { status: 302, headers: { Location: location } });
93
- }
94
- return buildResponse(await resp.json(), resp.status, getMirroredCookie(resp));
95
- }
96
- /** Handle POST requests (login, 2FA, password changes, etc.) */
97
- export async function handleAuthPost(rawEndpoint, request, url, locals) {
98
- if (!ALLOWED_AUTH_METHODS.includes(request.method))
99
- return jsonError('Method not allowed', 405);
100
- const contentLength = request.headers.get('content-length');
101
- if (contentLength && parseInt(contentLength) > MAX_BODY_SIZE_BYTES)
102
- return jsonError('Payload too large', 413);
103
- // ASTRO 6 CHANGE: Environment variables accessed from 'cloudflare:workers' env directly.
104
- const internalApiKey = env.INTERNAL_API_KEY || import.meta.env.INTERNAL_API_KEY;
105
- if (!internalApiKey)
106
- console.error('[auth-handler] INTERNAL_API_KEY not configured');
107
- const endpoint = sanitizeEndpoint(rawEndpoint);
108
- if (!endpoint)
109
- return jsonError('Bad request', 400);
110
- // Parse request body
111
- let body = null;
112
- try {
113
- const text = await request.text();
114
- if (text) {
115
- JSON.parse(text);
116
- body = text;
117
- }
118
- }
119
- catch {
120
- return jsonError('Invalid JSON', 400);
121
- }
122
- let resp;
123
- try {
124
- resp = await fetchWithTimeout(`${CENTRAL_AUTH_ORIGIN}/auth/${endpoint}`, {
125
- method: 'POST',
126
- headers: buildProxyHeaders(request, url.hostname, internalApiKey),
127
- body
128
- });
129
- }
130
- catch (e) {
131
- if (e.name === 'AbortError')
132
- return jsonError('Request timeout', 504);
133
- throw e;
134
- }
135
- const data = await resp.json();
136
- const cookie = getMirroredCookie(resp);
137
- // Handle HTTP redirect
138
- const location = resp.headers.get('Location');
139
- if (resp.status === 302 && location && isSafeRedirect(location)) {
140
- return new Response(null, { status: 302, headers: { Location: location } });
141
- }
142
- // Handle JSON redirect (loginsuccessredirect)
143
- const redirectUrl = data.loginsuccessredirect;
144
- if (typeof redirectUrl === 'string' && isSafeRedirect(redirectUrl)) {
145
- return new Response(null, {
146
- status: 302,
147
- headers: { Location: redirectUrl, ...(cookie && { 'Set-Cookie': cookie }) }
148
- });
149
- }
150
- // Remove sensitive data
151
- delete data.sessionToken;
152
- delete data.maxAgeSeconds;
153
- return buildResponse(data, resp.status, cookie);
154
- }
package/dist/auth.d.ts DELETED
@@ -1,9 +0,0 @@
1
- import type { SessionValidationResult } from './types';
2
- /** Validate session with Mindful Auth central service */
3
- export declare function validateSession(request: Request, tenantDomain: string, pathname: string, internalApiKey: string): Promise<SessionValidationResult>;
4
- /** Validate memberid in URL matches session (or just check structure if sessionRecordId is null) */
5
- export declare function validateMemberIdInUrl(pathname: string, sessionRecordId: string | null): {
6
- valid: boolean;
7
- strippedPathname?: string;
8
- };
9
- //# sourceMappingURL=auth.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAEvD,yDAAyD;AACzD,wBAAsB,eAAe,CACjC,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,GACvB,OAAO,CAAC,uBAAuB,CAAC,CAsClC;AAED,oGAAoG;AACpG,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,CAerI"}
package/dist/auth.js DELETED
@@ -1,56 +0,0 @@
1
- // Authentication and session validation for Mindful Auth
2
- import { CENTRAL_AUTH_ORIGIN, SESSION_VALIDATION_TIMEOUT_MS } from './config';
3
- /** Validate session with Mindful Auth central service */
4
- export async function validateSession(request, tenantDomain, pathname, internalApiKey) {
5
- const sessionId = request.headers.get('Cookie')?.match(/session_id=([^;]+)/)?.[1];
6
- if (!sessionId)
7
- return { valid: false, reason: 'no-session' };
8
- const controller = new AbortController();
9
- const timeoutId = setTimeout(() => controller.abort(), SESSION_VALIDATION_TIMEOUT_MS);
10
- try {
11
- const clientIp = request.headers.get('cf-connecting-ip') ||
12
- request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ||
13
- request.headers.get('x-real-ip');
14
- const resp = await fetch(`${CENTRAL_AUTH_ORIGIN}/auth/validate-session`, {
15
- method: 'POST',
16
- headers: {
17
- 'Content-Type': 'application/json',
18
- 'X-Tenant-Domain': tenantDomain,
19
- 'X-Internal-Api-Key': internalApiKey,
20
- ...(clientIp && { 'X-Original-Client-IP': clientIp }),
21
- ...(request.headers.get('user-agent') && { 'User-Agent': request.headers.get('user-agent') })
22
- },
23
- body: JSON.stringify({ sessionId, requestedUrl: pathname }),
24
- signal: controller.signal
25
- });
26
- const result = await resp.json();
27
- if (!result.valid)
28
- return { valid: false, reason: 'invalid-session' };
29
- const recordId = result.data?.sub || result.recordId;
30
- if (!recordId)
31
- return { valid: false, reason: 'invalid-record-id' };
32
- return { valid: true, recordId };
33
- }
34
- catch (e) {
35
- console.error('[auth] Session validation failed:', e.message);
36
- return { valid: false, reason: 'error' };
37
- }
38
- finally {
39
- clearTimeout(timeoutId);
40
- }
41
- }
42
- /** Validate memberid in URL matches session (or just check structure if sessionRecordId is null) */
43
- export function validateMemberIdInUrl(pathname, sessionRecordId) {
44
- const segments = pathname.split('/').filter(Boolean);
45
- if (segments.length === 0)
46
- return { valid: false };
47
- const urlMemberId = segments[0];
48
- // Pre-check mode: just validate URL has memberid
49
- if (sessionRecordId === null) {
50
- return { valid: !!urlMemberId, strippedPathname: pathname };
51
- }
52
- // Validate memberid matches session
53
- if (urlMemberId !== sessionRecordId)
54
- return { valid: false };
55
- return { valid: true, strippedPathname: '/' + segments.slice(1).join('/') };
56
- }
package/dist/config.d.ts DELETED
@@ -1,49 +0,0 @@
1
- export declare const CENTRAL_AUTH_ORIGIN = "https://api.mindfulauth.com";
2
- export declare const CDN_ORIGIN = "https://cdn.mindfulauth.com";
3
- export declare const ALLOWED_AUTH_METHODS: string[];
4
- export declare const MAX_BODY_SIZE_BYTES = 1048576;
5
- export declare const AUTH_PROXY_TIMEOUT_MS = 15000;
6
- export declare const SESSION_VALIDATION_TIMEOUT_MS = 10000;
7
- /**
8
- * Returns the combined list of assets to skip session validation for.
9
- * Merges defaults with any custom assets configured via mauthSecurityConfig() in astro.config.mjs.
10
- */
11
- export declare function GET_SKIP_ASSETS(): string[];
12
- /**
13
- * Configure Mindful Auth security settings including custom skip assets.
14
- * Call in astro.config.mjs and pass the result to getMauthViteDefines().
15
- *
16
- * @example
17
- * // astro.config.mjs
18
- * const mauthCfg = mauthSecurityConfig({
19
- * skipAssets: ['/sitemap.xml', '/manifest.webmanifest']
20
- * });
21
- *
22
- * export default defineConfig({
23
- * vite: { define: getMauthViteDefines(mauthCfg) }
24
- * });
25
- */
26
- export declare function mauthSecurityConfig(options?: {
27
- skipAssets?: string[];
28
- }): typeof options;
29
- /**
30
- * Converts the result of mauthSecurityConfig() into Vite define entries.
31
- * Pass the output to vite.define in astro.config.mjs so custom values are
32
- * baked into the SSR bundle at build time.
33
- */
34
- export declare function getMauthViteDefines(options?: {
35
- skipAssets?: string[];
36
- }): Record<string, string>;
37
- export declare const PUBLIC_ROUTES: string[];
38
- export declare const PUBLIC_PREFIXES: string[];
39
- /**
40
- * Returns security headers to be added to every SSR response.
41
- * CSP (Content-Security-Policy) for script-src and style-src is handled by
42
- * Astro 6's native security.csp in astro.config.mjs using hashes.
43
- * The remaining headers here cover transport security, framing, and permissions.
44
- *
45
- * Note: X-Frame-Options: SAMEORIGIN covers clickjacking protection
46
- * (equivalent to CSP frame-ancestors 'self', which cannot be set via meta tag).
47
- */
48
- export declare function GET_SECURITY_HEADERS(): Record<string, string>;
49
- //# sourceMappingURL=config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,gCAAgC,CAAC;AACjE,eAAO,MAAM,UAAU,gCAAgC,CAAC;AAGxD,eAAO,MAAM,oBAAoB,UAAkB,CAAC;AACpD,eAAO,MAAM,mBAAmB,UAAU,CAAC;AAC3C,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAC3C,eAAO,MAAM,6BAA6B,QAAQ,CAAC;AAenD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE;IAC1C,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,GAAG,OAAO,OAAO,CAEjB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE;IAC1C,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIzB;AAID,eAAO,MAAM,aAAa,UAQzB,CAAC;AAIF,eAAO,MAAM,eAAe,UAO3B,CAAC;AAMF;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ7D"}
package/dist/config.js DELETED
@@ -1,95 +0,0 @@
1
- // ============================================================================
2
- // Configuration for the Astro Portal
3
- // ============================================================================
4
- // API Endpoints
5
- export const CENTRAL_AUTH_ORIGIN = 'https://api.mindfulauth.com';
6
- export const CDN_ORIGIN = 'https://cdn.mindfulauth.com';
7
- // Request & Timeout Configuration
8
- export const ALLOWED_AUTH_METHODS = ['GET', 'POST'];
9
- export const MAX_BODY_SIZE_BYTES = 1048576; // 1MB limit
10
- export const AUTH_PROXY_TIMEOUT_MS = 15000;
11
- export const SESSION_VALIDATION_TIMEOUT_MS = 10000;
12
- // ============================================================================
13
- // Static Assets & Route Configuration
14
- // ============================================================================
15
- // Static assets to skip session validation (favicon, robots.txt, etc.)
16
- // SECURITY CRITICAL: Only add actual static file requests here.
17
- // Examples of safe entries: /favicon.ico, /robots.txt, /sitemap.xml
18
- // NEVER add application routes like [memberid]/dashboard, [memberid]/profile, [memberid]/secure/* - this COMPLETELY bypasses authentication. If you add a route here, unauthenticated users can access it without logging in.
19
- const DEFAULT_SKIP_ASSETS = ['/favicon.ico', '/robots.txt', '/.well-known/security.txt'];
20
- /**
21
- * Returns the combined list of assets to skip session validation for.
22
- * Merges defaults with any custom assets configured via mauthSecurityConfig() in astro.config.mjs.
23
- */
24
- export function GET_SKIP_ASSETS() {
25
- return [...DEFAULT_SKIP_ASSETS, ...__MAUTH_SKIP_ASSETS__];
26
- }
27
- /**
28
- * Configure Mindful Auth security settings including custom skip assets.
29
- * Call in astro.config.mjs and pass the result to getMauthViteDefines().
30
- *
31
- * @example
32
- * // astro.config.mjs
33
- * const mauthCfg = mauthSecurityConfig({
34
- * skipAssets: ['/sitemap.xml', '/manifest.webmanifest']
35
- * });
36
- *
37
- * export default defineConfig({
38
- * vite: { define: getMauthViteDefines(mauthCfg) }
39
- * });
40
- */
41
- export function mauthSecurityConfig(options) {
42
- return options;
43
- }
44
- /**
45
- * Converts the result of mauthSecurityConfig() into Vite define entries.
46
- * Pass the output to vite.define in astro.config.mjs so custom values are
47
- * baked into the SSR bundle at build time.
48
- */
49
- export function getMauthViteDefines(options) {
50
- return {
51
- __MAUTH_SKIP_ASSETS__: JSON.stringify(options?.skipAssets ?? []),
52
- };
53
- }
54
- // Public routes that do not require authentication
55
- // ⚠️ DO NOT EDIT - These are critical for the authentication system to work correctly
56
- export const PUBLIC_ROUTES = [
57
- '/',
58
- '/login',
59
- '/register',
60
- '/magic-login',
61
- '/magic-register',
62
- '/forgot-password',
63
- '/resend-verification',
64
- ];
65
- // Dynamic public routes (prefix matching)
66
- // ⚠️ DO NOT EDIT - These are critical for the authentication system to work correctly
67
- export const PUBLIC_PREFIXES = [
68
- '/auth/',
69
- '/email-verified/',
70
- '/reset-password/',
71
- '/verify-email/',
72
- '/verify-magic-link/',
73
- '/api/public/',
74
- ];
75
- // ============================================================================
76
- // Security Headers
77
- // ============================================================================
78
- /**
79
- * Returns security headers to be added to every SSR response.
80
- * CSP (Content-Security-Policy) for script-src and style-src is handled by
81
- * Astro 6's native security.csp in astro.config.mjs using hashes.
82
- * The remaining headers here cover transport security, framing, and permissions.
83
- *
84
- * Note: X-Frame-Options: SAMEORIGIN covers clickjacking protection
85
- * (equivalent to CSP frame-ancestors 'self', which cannot be set via meta tag).
86
- */
87
- export function GET_SECURITY_HEADERS() {
88
- return {
89
- 'X-Content-Type-Options': 'nosniff',
90
- 'X-Frame-Options': 'SAMEORIGIN',
91
- 'Referrer-Policy': 'strict-origin-when-cross-origin',
92
- 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
93
- 'Permissions-Policy': 'geolocation=(), microphone=(), camera=()',
94
- };
95
- }
package/dist/index.d.ts DELETED
@@ -1,7 +0,0 @@
1
- export * from './types';
2
- export * from './config';
3
- export * from './auth';
4
- export * from './auth-handler';
5
- export * from './security';
6
- export * from './middleware';
7
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,SAAS,CAAC;AAGxB,cAAc,UAAU,CAAC;AAGzB,cAAc,QAAQ,CAAC;AAGvB,cAAc,gBAAgB,CAAC;AAG/B,cAAc,YAAY,CAAC;AAG3B,cAAc,cAAc,CAAC"}
package/dist/index.js DELETED
@@ -1,13 +0,0 @@
1
- // Mindful Auth Core - Main exports
2
- // Types
3
- export * from './types';
4
- // Configuration
5
- export * from './config';
6
- // Authentication
7
- export * from './auth';
8
- // Auth handler for API routes
9
- export * from './auth-handler';
10
- // Security utilities
11
- export * from './security';
12
- // Middleware
13
- export * from './middleware';
@@ -1,2 +0,0 @@
1
- export declare const onRequest: import("astro").MiddlewareHandler;
2
- //# sourceMappingURL=middleware.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAqCA,eAAO,MAAM,SAAS,mCAqFpB,CAAC"}