@coreiam/auth 1.0.1 → 1.0.4

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.
@@ -4,10 +4,6 @@ export interface AuthResult {
4
4
  status: number;
5
5
  data: any;
6
6
  }
7
- /**
8
- * NEW: Securely gets the user session.
9
- * Handles 401 by attempting a silent refresh internally.
10
- */
11
7
  export declare function getSession(): Promise<CoreIAMIdentity | null>;
12
8
  export declare function loginActionSdk(identifier: string, password: string): Promise<AuthResult>;
13
9
  export declare function registerActionSdk(userData: any): Promise<AuthResult>;
@@ -29,21 +29,17 @@ async function syncCookiesToNext(response) {
29
29
  cookieOptions.path = attrValue || '/';
30
30
  if (lowerName === 'max-age') {
31
31
  const maxAge = parseInt(attrValue, 10);
32
- if (maxAge <= 0) {
32
+ if (maxAge <= 0)
33
33
  isDeleting = true;
34
- }
35
- else {
34
+ else
36
35
  cookieOptions.maxAge = maxAge;
37
- }
38
36
  }
39
37
  if (lowerName === 'expires') {
40
38
  const expiryDate = new Date(attrValue);
41
- if (expiryDate.getTime() < Date.now()) {
39
+ if (expiryDate.getTime() < Date.now())
42
40
  isDeleting = true;
43
- }
44
- else {
41
+ else
45
42
  cookieOptions.expires = expiryDate;
46
- }
47
43
  }
48
44
  if (lowerName === 'samesite')
49
45
  cookieOptions.sameSite = attrValue?.toLowerCase() || 'lax';
@@ -58,38 +54,14 @@ async function syncCookiesToNext(response) {
58
54
  }
59
55
  }
60
56
  }
61
- /**
62
- * NEW: Securely gets the user session.
63
- * Handles 401 by attempting a silent refresh internally.
64
- */
65
57
  async function getSession() {
66
58
  const reqHeaders = await (0, headers_1.headers)();
67
- let response = await iam.proxy('/auth/profile', { method: 'GET' }, reqHeaders);
68
- if (response.status === 401) {
69
- const refreshRes = await iam.proxy('/auth/refresh-token', { method: 'POST' }, reqHeaders);
70
- if (refreshRes.ok) {
71
- const setCookies = refreshRes.headers.getSetCookie();
72
- if (setCookies && setCookies.length > 0) {
73
- const fakeRes = new Response(null, { headers: { 'set-cookie': setCookies.join(', ') } });
74
- await syncCookiesToNext(fakeRes);
75
- const cookieStore = await (0, headers_1.cookies)();
76
- const newJwt = cookieStore.get('jwt')?.value;
77
- const newRefresh = cookieStore.get('refreshToken')?.value;
78
- const retryHeaders = new Headers(reqHeaders);
79
- if (newJwt && newRefresh) {
80
- retryHeaders.set('cookie', `jwt=${newJwt}; refreshToken=${newRefresh}`);
81
- retryHeaders.set('Authorization', `Bearer ${newJwt}`);
82
- }
83
- response = await iam.proxy('/auth/profile', { method: 'GET' }, retryHeaders);
84
- }
85
- }
86
- }
59
+ const response = await iam.proxy('/auth/profile', { method: 'GET' }, reqHeaders);
87
60
  if (!response.ok)
88
61
  return null;
89
62
  const coreIamIdentity = await response.json();
90
63
  if (!coreIamIdentity?.sub)
91
64
  return null;
92
- // Return the Provider's Identity, NOT the Customer's User
93
65
  return coreIamIdentity;
94
66
  }
95
67
  async function loginActionSdk(identifier, password) {
@@ -1,5 +1,6 @@
1
1
  export { CoreIAMProvider, useAuth } from './provider';
2
2
  export { loginActionSdk, registerActionSdk, logoutActionSdk, getSession } from './actions';
3
+ export { coreIamMiddleware } from './middleware';
3
4
  import { NextRequest, NextResponse } from 'next/server';
4
5
  import { CoreIAM } from '../core';
5
6
  export declare class NextHandlers {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NextHandlers = exports.getSession = exports.logoutActionSdk = exports.registerActionSdk = exports.loginActionSdk = exports.useAuth = exports.CoreIAMProvider = void 0;
3
+ exports.NextHandlers = exports.coreIamMiddleware = exports.getSession = exports.logoutActionSdk = exports.registerActionSdk = exports.loginActionSdk = exports.useAuth = exports.CoreIAMProvider = void 0;
4
4
  // src/nextjs/index.ts
5
5
  var provider_1 = require("./provider");
6
6
  Object.defineProperty(exports, "CoreIAMProvider", { enumerable: true, get: function () { return provider_1.CoreIAMProvider; } });
@@ -10,6 +10,8 @@ Object.defineProperty(exports, "loginActionSdk", { enumerable: true, get: functi
10
10
  Object.defineProperty(exports, "registerActionSdk", { enumerable: true, get: function () { return actions_1.registerActionSdk; } });
11
11
  Object.defineProperty(exports, "logoutActionSdk", { enumerable: true, get: function () { return actions_1.logoutActionSdk; } });
12
12
  Object.defineProperty(exports, "getSession", { enumerable: true, get: function () { return actions_1.getSession; } });
13
+ var middleware_1 = require("./middleware");
14
+ Object.defineProperty(exports, "coreIamMiddleware", { enumerable: true, get: function () { return middleware_1.coreIamMiddleware; } });
13
15
  const server_1 = require("next/server");
14
16
  class NextHandlers {
15
17
  iam;
@@ -0,0 +1,2 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ export declare function coreIamMiddleware(): (request: NextRequest) => Promise<NextResponse<unknown>>;
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.coreIamMiddleware = coreIamMiddleware;
4
+ // src/nextjs/middleware.ts
5
+ const server_1 = require("next/server");
6
+ const jwt_decode_1 = require("jwt-decode");
7
+ const DEFAULT_GATEWAY_URL = "https://api.e-qalam.com";
8
+ function coreIamMiddleware() {
9
+ return async function middleware(request) {
10
+ const { nextUrl } = request;
11
+ const pathname = nextUrl.pathname;
12
+ const jwtCookie = request.cookies.get("jwt");
13
+ const refreshTokenCookie = request.cookies.get("refreshToken");
14
+ let isLoggedIn = false;
15
+ let needsRefresh = false;
16
+ if (jwtCookie) {
17
+ try {
18
+ const decoded = (0, jwt_decode_1.jwtDecode)(jwtCookie.value);
19
+ if (decoded.exp && decoded.exp * 1000 > Date.now()) {
20
+ isLoggedIn = true;
21
+ }
22
+ else {
23
+ if (refreshTokenCookie)
24
+ needsRefresh = true;
25
+ }
26
+ }
27
+ catch {
28
+ if (refreshTokenCookie)
29
+ needsRefresh = true;
30
+ }
31
+ }
32
+ else if (refreshTokenCookie) {
33
+ needsRefresh = true;
34
+ }
35
+ // Allow API routes to pass through (we handle their 401s normally)
36
+ if (pathname.startsWith('/api')) {
37
+ return server_1.NextResponse.next();
38
+ }
39
+ // 1. ATTEMPT SILENT REFRESH
40
+ if (needsRefresh) {
41
+ try {
42
+ const refreshRes = await fetch(`${DEFAULT_GATEWAY_URL}/auth/refresh-token`, {
43
+ method: 'POST',
44
+ headers: {
45
+ 'X-API-Key': process.env.COREIAM_API_KEY,
46
+ 'cookie': `refreshToken=${refreshTokenCookie?.value || ''}; jwt=${jwtCookie?.value || ''}`,
47
+ },
48
+ });
49
+ if (refreshRes.ok) {
50
+ const setCookies = refreshRes.headers.getSetCookie();
51
+ if (setCookies && setCookies.length > 0) {
52
+ let newJwt = '';
53
+ let newRefreshToken = '';
54
+ setCookies.forEach(cookie => {
55
+ if (cookie.startsWith('jwt='))
56
+ newJwt = cookie.split(';')[0].split('=')[1];
57
+ if (cookie.startsWith('refreshToken='))
58
+ newRefreshToken = cookie.split(';')[0].split('=')[1];
59
+ });
60
+ // CRITICAL: Rewrite request headers so Server Components see the new JWT!
61
+ const requestHeaders = new Headers(request.headers);
62
+ requestHeaders.set('cookie', `jwt=${newJwt}; refreshToken=${newRefreshToken}`);
63
+ requestHeaders.set('Authorization', `Bearer ${newJwt}`);
64
+ const response = server_1.NextResponse.next({
65
+ request: { headers: requestHeaders },
66
+ });
67
+ // Set the new cookies on the browser
68
+ setCookies.forEach(cookie => {
69
+ response.headers.append('set-cookie', cookie);
70
+ });
71
+ return response; // Exit early, token is fresh!
72
+ }
73
+ }
74
+ }
75
+ catch (error) {
76
+ // Refresh failed, fall through to clear cookies
77
+ }
78
+ // 2. IF REFRESH FAILED, CLEAR COOKIES TO PREVENT INFINITE LOOP
79
+ const res = server_1.NextResponse.redirect(new URL('/auth/login', nextUrl));
80
+ res.cookies.delete('jwt');
81
+ res.cookies.delete('refreshToken');
82
+ return res;
83
+ }
84
+ // 3. STANDARD ROUTE PROTECTION
85
+ const isAuthRoute = pathname.startsWith('/auth/login') || pathname.startsWith('/auth/register');
86
+ if (isAuthRoute && isLoggedIn) {
87
+ return server_1.NextResponse.redirect(new URL('/', nextUrl));
88
+ }
89
+ if (!isLoggedIn && !isAuthRoute) {
90
+ return server_1.NextResponse.redirect(new URL('/auth/login', nextUrl));
91
+ }
92
+ return server_1.NextResponse.next();
93
+ };
94
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coreiam/auth",
3
- "version": "1.0.1",
3
+ "version": "1.0.4",
4
4
  "main": "./dist/core/index.js",
5
5
  "types": "./dist/core/index.d.ts",
6
6
  "exports": {
@@ -20,26 +20,43 @@
20
20
  "require": "./dist/react/index.js"
21
21
  }
22
22
  },
23
- "files": ["dist"],
23
+ "files": [
24
+ "dist"
25
+ ],
24
26
  "scripts": {
25
27
  "build": "tsc"
26
28
  },
27
- "keywords": ["coreiam", "auth", "saas", "multi-tenant", "nextjs"],
29
+ "keywords": [
30
+ "coreiam",
31
+ "auth",
32
+ "saas",
33
+ "multi-tenant",
34
+ "nextjs"
35
+ ],
28
36
  "author": "coreIAM",
29
37
  "license": "MIT",
30
- "publishConfig": { "access": "public" },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
31
41
  "peerDependencies": {
32
42
  "next": ">=14",
33
43
  "react": ">=18"
34
44
  },
35
45
  "peerDependenciesMeta": {
36
- "next": { "optional": true },
37
- "react": { "optional": true }
46
+ "next": {
47
+ "optional": true
48
+ },
49
+ "react": {
50
+ "optional": true
51
+ }
38
52
  },
39
53
  "devDependencies": {
40
54
  "@types/react": "^19.2.7",
41
55
  "next": "^16.2.11",
42
56
  "react": "^19.2.7",
43
57
  "typescript": "^5.0.0"
58
+ },
59
+ "dependencies": {
60
+ "jwt-decode": "^4.0.0"
44
61
  }
45
62
  }