@fnd-platform/cognito-auth 1.0.0-alpha.2 → 1.0.0-alpha.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.
- package/LICENSE +21 -0
- package/lib/remix/admin.server.js +44 -45
- package/lib/remix/index.d.ts +3 -11
- package/lib/remix/index.d.ts.map +1 -1
- package/lib/remix/index.js +19 -90
- package/lib/remix/index.js.map +1 -1
- package/lib/remix/session.server.d.ts +43 -33
- package/lib/remix/session.server.d.ts.map +1 -1
- package/lib/remix/session.server.js +60 -7
- package/lib/remix/session.server.js.map +1 -1
- package/package.json +9 -9
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 fnd-platform contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* Admin and role-based access utilities for Remix.
|
|
4
4
|
*
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @packageDocumentation
|
|
8
8
|
*/
|
|
9
|
-
Object.defineProperty(exports,
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.requireAdmin = requireAdmin;
|
|
11
11
|
exports.requireRole = requireRole;
|
|
12
12
|
exports.hasRole = hasRole;
|
|
13
13
|
exports.hasAnyRole = hasAnyRole;
|
|
14
|
-
const node_1 = require(
|
|
15
|
-
const session_server_js_1 = require(
|
|
14
|
+
const node_1 = require("@remix-run/node");
|
|
15
|
+
const session_server_js_1 = require("./session.server.js");
|
|
16
16
|
/**
|
|
17
17
|
* Requires admin role for accessing a route.
|
|
18
18
|
*
|
|
@@ -35,7 +35,7 @@ const session_server_js_1 = require('./session.server.js');
|
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
37
|
async function requireAdmin(request, storage) {
|
|
38
|
-
|
|
38
|
+
return requireRole(request, ['admin'], storage);
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
41
|
* Requires any of the specified roles for accessing a route.
|
|
@@ -60,25 +60,22 @@ async function requireAdmin(request, storage) {
|
|
|
60
60
|
* ```
|
|
61
61
|
*/
|
|
62
62
|
async function requireRole(request, roles, storage) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
return userId;
|
|
63
|
+
// First ensure user is authenticated
|
|
64
|
+
const userId = await (0, session_server_js_1.requireAuth)(request, '/login', storage);
|
|
65
|
+
// Get user's groups from session
|
|
66
|
+
const session = await (0, session_server_js_1.getSession)(request, storage);
|
|
67
|
+
const userGroups = session.get('groups') ?? [];
|
|
68
|
+
// Check if user has at least one required role
|
|
69
|
+
const hasRequiredRole = roles.some((role) => userGroups.includes(role));
|
|
70
|
+
if (!hasRequiredRole) {
|
|
71
|
+
throw (0, node_1.json)({
|
|
72
|
+
error: {
|
|
73
|
+
code: 'FORBIDDEN',
|
|
74
|
+
message: `Required role: ${roles.join(' or ')}`,
|
|
75
|
+
},
|
|
76
|
+
}, { status: 403 });
|
|
77
|
+
}
|
|
78
|
+
return userId;
|
|
82
79
|
}
|
|
83
80
|
/**
|
|
84
81
|
* Checks if the user has a specific role.
|
|
@@ -100,17 +97,18 @@ async function requireRole(request, roles, storage) {
|
|
|
100
97
|
* ```
|
|
101
98
|
*/
|
|
102
99
|
async function hasRole(request, role, storage) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
100
|
+
try {
|
|
101
|
+
const session = await (0, session_server_js_1.getSession)(request, storage);
|
|
102
|
+
const userId = session.get('userId');
|
|
103
|
+
if (!userId) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const userGroups = session.get('groups') ?? [];
|
|
107
|
+
return userGroups.includes(role);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return false;
|
|
108
111
|
}
|
|
109
|
-
const userGroups = session.get('groups') ?? [];
|
|
110
|
-
return userGroups.includes(role);
|
|
111
|
-
} catch {
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
112
|
}
|
|
115
113
|
/**
|
|
116
114
|
* Checks if the user has any of the specified roles.
|
|
@@ -131,16 +129,17 @@ async function hasRole(request, role, storage) {
|
|
|
131
129
|
* ```
|
|
132
130
|
*/
|
|
133
131
|
async function hasAnyRole(request, roles, storage) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
132
|
+
try {
|
|
133
|
+
const session = await (0, session_server_js_1.getSession)(request, storage);
|
|
134
|
+
const userId = session.get('userId');
|
|
135
|
+
if (!userId) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
const userGroups = session.get('groups') ?? [];
|
|
139
|
+
return roles.some((role) => userGroups.includes(role));
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return false;
|
|
139
143
|
}
|
|
140
|
-
const userGroups = session.get('groups') ?? [];
|
|
141
|
-
return roles.some((role) => userGroups.includes(role));
|
|
142
|
-
} catch {
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
144
|
}
|
|
146
|
-
//# sourceMappingURL=admin.server.js.map
|
|
145
|
+
//# sourceMappingURL=admin.server.js.map
|
package/lib/remix/index.d.ts
CHANGED
|
@@ -3,15 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @packageDocumentation
|
|
5
5
|
*/
|
|
6
|
-
export {
|
|
7
|
-
|
|
8
|
-
getSession,
|
|
9
|
-
createUserSession,
|
|
10
|
-
requireAuth,
|
|
11
|
-
getOptionalUser,
|
|
12
|
-
getUserSession,
|
|
13
|
-
logout,
|
|
14
|
-
resetDefaultStorage,
|
|
15
|
-
} from './session.server.js';
|
|
6
|
+
export { createSessionStorage, getSession, createUserSession, requireAuth, getOptionalUser, getUserSession, getAccessToken, logout, resetDefaultStorage, } from './session.server.js';
|
|
7
|
+
export type { GetAccessTokenConfig } from './session.server.js';
|
|
16
8
|
export { requireAdmin, requireRole, hasRole, hasAnyRole } from './admin.server.js';
|
|
17
|
-
//# sourceMappingURL=index.d.ts.map
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
package/lib/remix/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/remix/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,oBAAoB,EACpB,UAAU,EACV,iBAAiB,EACjB,WAAW,EACX,eAAe,EACf,cAAc,EACd,MAAM,EACN,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/remix/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,oBAAoB,EACpB,UAAU,EACV,iBAAiB,EACjB,WAAW,EACX,eAAe,EACf,cAAc,EACd,cAAc,EACd,MAAM,EACN,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEhE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
|
package/lib/remix/index.js
CHANGED
|
@@ -1,95 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* Remix authentication utilities exports.
|
|
4
4
|
*
|
|
5
5
|
* @packageDocumentation
|
|
6
6
|
*/
|
|
7
|
-
Object.defineProperty(exports,
|
|
8
|
-
exports.hasAnyRole =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
Object.defineProperty(exports,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return session_server_js_1.createSessionStorage;
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
Object.defineProperty(exports, 'getSession', {
|
|
29
|
-
enumerable: true,
|
|
30
|
-
get: function () {
|
|
31
|
-
return session_server_js_1.getSession;
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
Object.defineProperty(exports, 'createUserSession', {
|
|
35
|
-
enumerable: true,
|
|
36
|
-
get: function () {
|
|
37
|
-
return session_server_js_1.createUserSession;
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
Object.defineProperty(exports, 'requireAuth', {
|
|
41
|
-
enumerable: true,
|
|
42
|
-
get: function () {
|
|
43
|
-
return session_server_js_1.requireAuth;
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
Object.defineProperty(exports, 'getOptionalUser', {
|
|
47
|
-
enumerable: true,
|
|
48
|
-
get: function () {
|
|
49
|
-
return session_server_js_1.getOptionalUser;
|
|
50
|
-
},
|
|
51
|
-
});
|
|
52
|
-
Object.defineProperty(exports, 'getUserSession', {
|
|
53
|
-
enumerable: true,
|
|
54
|
-
get: function () {
|
|
55
|
-
return session_server_js_1.getUserSession;
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
Object.defineProperty(exports, 'logout', {
|
|
59
|
-
enumerable: true,
|
|
60
|
-
get: function () {
|
|
61
|
-
return session_server_js_1.logout;
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
Object.defineProperty(exports, 'resetDefaultStorage', {
|
|
65
|
-
enumerable: true,
|
|
66
|
-
get: function () {
|
|
67
|
-
return session_server_js_1.resetDefaultStorage;
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
var admin_server_js_1 = require('./admin.server.js');
|
|
71
|
-
Object.defineProperty(exports, 'requireAdmin', {
|
|
72
|
-
enumerable: true,
|
|
73
|
-
get: function () {
|
|
74
|
-
return admin_server_js_1.requireAdmin;
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
Object.defineProperty(exports, 'requireRole', {
|
|
78
|
-
enumerable: true,
|
|
79
|
-
get: function () {
|
|
80
|
-
return admin_server_js_1.requireRole;
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
Object.defineProperty(exports, 'hasRole', {
|
|
84
|
-
enumerable: true,
|
|
85
|
-
get: function () {
|
|
86
|
-
return admin_server_js_1.hasRole;
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
Object.defineProperty(exports, 'hasAnyRole', {
|
|
90
|
-
enumerable: true,
|
|
91
|
-
get: function () {
|
|
92
|
-
return admin_server_js_1.hasAnyRole;
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
//# sourceMappingURL=index.js.map
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.hasAnyRole = exports.hasRole = exports.requireRole = exports.requireAdmin = exports.resetDefaultStorage = exports.logout = exports.getAccessToken = exports.getUserSession = exports.getOptionalUser = exports.requireAuth = exports.createUserSession = exports.getSession = exports.createSessionStorage = void 0;
|
|
9
|
+
var session_server_js_1 = require("./session.server.js");
|
|
10
|
+
Object.defineProperty(exports, "createSessionStorage", { enumerable: true, get: function () { return session_server_js_1.createSessionStorage; } });
|
|
11
|
+
Object.defineProperty(exports, "getSession", { enumerable: true, get: function () { return session_server_js_1.getSession; } });
|
|
12
|
+
Object.defineProperty(exports, "createUserSession", { enumerable: true, get: function () { return session_server_js_1.createUserSession; } });
|
|
13
|
+
Object.defineProperty(exports, "requireAuth", { enumerable: true, get: function () { return session_server_js_1.requireAuth; } });
|
|
14
|
+
Object.defineProperty(exports, "getOptionalUser", { enumerable: true, get: function () { return session_server_js_1.getOptionalUser; } });
|
|
15
|
+
Object.defineProperty(exports, "getUserSession", { enumerable: true, get: function () { return session_server_js_1.getUserSession; } });
|
|
16
|
+
Object.defineProperty(exports, "getAccessToken", { enumerable: true, get: function () { return session_server_js_1.getAccessToken; } });
|
|
17
|
+
Object.defineProperty(exports, "logout", { enumerable: true, get: function () { return session_server_js_1.logout; } });
|
|
18
|
+
Object.defineProperty(exports, "resetDefaultStorage", { enumerable: true, get: function () { return session_server_js_1.resetDefaultStorage; } });
|
|
19
|
+
var admin_server_js_1 = require("./admin.server.js");
|
|
20
|
+
Object.defineProperty(exports, "requireAdmin", { enumerable: true, get: function () { return admin_server_js_1.requireAdmin; } });
|
|
21
|
+
Object.defineProperty(exports, "requireRole", { enumerable: true, get: function () { return admin_server_js_1.requireRole; } });
|
|
22
|
+
Object.defineProperty(exports, "hasRole", { enumerable: true, get: function () { return admin_server_js_1.hasRole; } });
|
|
23
|
+
Object.defineProperty(exports, "hasAnyRole", { enumerable: true, get: function () { return admin_server_js_1.hasAnyRole; } });
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
package/lib/remix/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/remix/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/remix/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,yDAU6B;AAT3B,yHAAA,oBAAoB,OAAA;AACpB,+GAAA,UAAU,OAAA;AACV,sHAAA,iBAAiB,OAAA;AACjB,gHAAA,WAAW,OAAA;AACX,oHAAA,eAAe,OAAA;AACf,mHAAA,cAAc,OAAA;AACd,mHAAA,cAAc,OAAA;AACd,2GAAA,MAAM,OAAA;AACN,wHAAA,mBAAmB,OAAA;AAKrB,qDAAmF;AAA1E,+GAAA,YAAY,OAAA;AAAE,8GAAA,WAAW,OAAA;AAAE,0GAAA,OAAO,OAAA;AAAE,6GAAA,UAAU,OAAA"}
|
|
@@ -45,15 +45,7 @@ export declare function resetDefaultStorage(): void;
|
|
|
45
45
|
* }
|
|
46
46
|
* ```
|
|
47
47
|
*/
|
|
48
|
-
export declare function getSession(
|
|
49
|
-
request: Request,
|
|
50
|
-
storage?: SessionStorage
|
|
51
|
-
): Promise<
|
|
52
|
-
import('@remix-run/node').Session<
|
|
53
|
-
import('@remix-run/node').SessionData,
|
|
54
|
-
import('@remix-run/node').SessionData
|
|
55
|
-
>
|
|
56
|
-
>;
|
|
48
|
+
export declare function getSession(request: Request, storage?: SessionStorage): Promise<import("@remix-run/node").Session<import("@remix-run/node").SessionData, import("@remix-run/node").SessionData>>;
|
|
57
49
|
/**
|
|
58
50
|
* Creates a user session with authentication tokens and redirects.
|
|
59
51
|
*
|
|
@@ -73,11 +65,7 @@ export declare function getSession(
|
|
|
73
65
|
* }
|
|
74
66
|
* ```
|
|
75
67
|
*/
|
|
76
|
-
export declare function createUserSession(
|
|
77
|
-
tokens: AuthTokens,
|
|
78
|
-
redirectTo: string,
|
|
79
|
-
storage?: SessionStorage
|
|
80
|
-
): Promise<Response>;
|
|
68
|
+
export declare function createUserSession(tokens: AuthTokens, redirectTo: string, storage?: SessionStorage): Promise<Response>;
|
|
81
69
|
/**
|
|
82
70
|
* Requires authentication for a route.
|
|
83
71
|
*
|
|
@@ -99,11 +87,7 @@ export declare function createUserSession(
|
|
|
99
87
|
* }
|
|
100
88
|
* ```
|
|
101
89
|
*/
|
|
102
|
-
export declare function requireAuth(
|
|
103
|
-
request: Request,
|
|
104
|
-
redirectTo?: string,
|
|
105
|
-
storage?: SessionStorage
|
|
106
|
-
): Promise<string>;
|
|
90
|
+
export declare function requireAuth(request: Request, redirectTo?: string, storage?: SessionStorage): Promise<string>;
|
|
107
91
|
/**
|
|
108
92
|
* Gets the optional user from the session.
|
|
109
93
|
*
|
|
@@ -122,10 +106,7 @@ export declare function requireAuth(
|
|
|
122
106
|
* }
|
|
123
107
|
* ```
|
|
124
108
|
*/
|
|
125
|
-
export declare function getOptionalUser(
|
|
126
|
-
request: Request,
|
|
127
|
-
storage?: SessionStorage
|
|
128
|
-
): Promise<SessionUser | null>;
|
|
109
|
+
export declare function getOptionalUser(request: Request, storage?: SessionStorage): Promise<SessionUser | null>;
|
|
129
110
|
/**
|
|
130
111
|
* Gets full session data including tokens.
|
|
131
112
|
*
|
|
@@ -148,10 +129,7 @@ export declare function getOptionalUser(
|
|
|
148
129
|
* }
|
|
149
130
|
* ```
|
|
150
131
|
*/
|
|
151
|
-
export declare function getUserSession(
|
|
152
|
-
request: Request,
|
|
153
|
-
storage?: SessionStorage
|
|
154
|
-
): Promise<SessionData | null>;
|
|
132
|
+
export declare function getUserSession(request: Request, storage?: SessionStorage): Promise<SessionData | null>;
|
|
155
133
|
/**
|
|
156
134
|
* Logs out the user and redirects to the login page.
|
|
157
135
|
*
|
|
@@ -169,9 +147,41 @@ export declare function getUserSession(
|
|
|
169
147
|
* }
|
|
170
148
|
* ```
|
|
171
149
|
*/
|
|
172
|
-
export declare function logout(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
150
|
+
export declare function logout(request: Request, redirectTo?: string, storage?: SessionStorage): Promise<Response>;
|
|
151
|
+
/**
|
|
152
|
+
* Configuration for getting access tokens.
|
|
153
|
+
*/
|
|
154
|
+
export interface GetAccessTokenConfig {
|
|
155
|
+
/** Cognito User Pool Client ID (defaults to COGNITO_CLIENT_ID env var) */
|
|
156
|
+
clientId?: string;
|
|
157
|
+
/** AWS region (defaults to AWS_REGION env var) */
|
|
158
|
+
region?: string;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Gets a fresh access token for making authenticated API calls.
|
|
162
|
+
*
|
|
163
|
+
* Since access tokens are not stored in the session (to stay under cookie limits),
|
|
164
|
+
* this function uses the refresh token to obtain a fresh access token from Cognito.
|
|
165
|
+
*
|
|
166
|
+
* @param request - Remix request object
|
|
167
|
+
* @param config - Optional configuration
|
|
168
|
+
* @param storage - Optional custom session storage
|
|
169
|
+
* @returns Fresh access token or null if not authenticated
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* export async function loader({ request }: LoaderFunctionArgs) {
|
|
174
|
+
* const accessToken = await getAccessToken(request);
|
|
175
|
+
* if (!accessToken) {
|
|
176
|
+
* throw redirect('/login');
|
|
177
|
+
* }
|
|
178
|
+
*
|
|
179
|
+
* const response = await fetch('https://api.example.com/data', {
|
|
180
|
+
* headers: { Authorization: `Bearer ${accessToken}` },
|
|
181
|
+
* });
|
|
182
|
+
* return json(await response.json());
|
|
183
|
+
* }
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
export declare function getAccessToken(request: Request, config?: GetAccessTokenConfig, storage?: SessionStorage): Promise<string | null>;
|
|
187
|
+
//# sourceMappingURL=session.server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.server.d.ts","sourceRoot":"","sources":["../../src/remix/session.server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"session.server.d.ts","sourceRoot":"","sources":["../../src/remix/session.server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAoBxE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,cAAc,CAcpE;AAeD;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,cAAc,4HAG1E;AAoBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CAuBnB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,UAAU,SAAW,EACrB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAa7B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAmB7B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,MAAM,CAC1B,OAAO,EAAE,OAAO,EAChB,UAAU,SAAW,EACrB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CASnB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,oBAAoB,EAC7B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwBxB"}
|
|
@@ -16,7 +16,9 @@ exports.requireAuth = requireAuth;
|
|
|
16
16
|
exports.getOptionalUser = getOptionalUser;
|
|
17
17
|
exports.getUserSession = getUserSession;
|
|
18
18
|
exports.logout = logout;
|
|
19
|
+
exports.getAccessToken = getAccessToken;
|
|
19
20
|
const node_1 = require("@remix-run/node");
|
|
21
|
+
const token_refresh_js_1 = require("../utils/token-refresh.js");
|
|
20
22
|
/**
|
|
21
23
|
* Default session storage instance.
|
|
22
24
|
* Lazily initialized to avoid accessing env at module load.
|
|
@@ -141,9 +143,11 @@ async function createUserSession(tokens, redirectTo, storage) {
|
|
|
141
143
|
const session = await sessionStorage.getSession();
|
|
142
144
|
// Decode ID token to get user info
|
|
143
145
|
const payload = decodeTokenPayload(tokens.idToken);
|
|
144
|
-
// Store
|
|
145
|
-
//
|
|
146
|
-
//
|
|
146
|
+
// Store tokens and user info in session.
|
|
147
|
+
// Note: Cookies have a ~4KB limit. JWT tokens are typically 1-2KB each.
|
|
148
|
+
// We only store refreshToken (for obtaining fresh accessTokens when needed).
|
|
149
|
+
// We skip accessToken and idToken to stay under cookie limits.
|
|
150
|
+
// User info is extracted from idToken and stored separately.
|
|
147
151
|
session.set('refreshToken', tokens.refreshToken);
|
|
148
152
|
session.set('expiresAt', Date.now() + tokens.expiresIn * 1000);
|
|
149
153
|
session.set('userId', payload.sub);
|
|
@@ -250,10 +254,10 @@ async function getUserSession(request, storage) {
|
|
|
250
254
|
return null;
|
|
251
255
|
}
|
|
252
256
|
return {
|
|
253
|
-
//
|
|
254
|
-
// Use
|
|
255
|
-
accessToken:
|
|
256
|
-
idToken:
|
|
257
|
+
// accessToken and idToken are NOT stored to stay under ~4KB cookie limit.
|
|
258
|
+
// Use getAccessToken() to obtain a fresh accessToken when needed for API calls.
|
|
259
|
+
accessToken: undefined,
|
|
260
|
+
idToken: undefined,
|
|
257
261
|
refreshToken: session.get('refreshToken'),
|
|
258
262
|
expiresAt: session.get('expiresAt'),
|
|
259
263
|
userId,
|
|
@@ -287,4 +291,53 @@ async function logout(request, redirectTo = '/login', storage) {
|
|
|
287
291
|
},
|
|
288
292
|
});
|
|
289
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Gets a fresh access token for making authenticated API calls.
|
|
296
|
+
*
|
|
297
|
+
* Since access tokens are not stored in the session (to stay under cookie limits),
|
|
298
|
+
* this function uses the refresh token to obtain a fresh access token from Cognito.
|
|
299
|
+
*
|
|
300
|
+
* @param request - Remix request object
|
|
301
|
+
* @param config - Optional configuration
|
|
302
|
+
* @param storage - Optional custom session storage
|
|
303
|
+
* @returns Fresh access token or null if not authenticated
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```typescript
|
|
307
|
+
* export async function loader({ request }: LoaderFunctionArgs) {
|
|
308
|
+
* const accessToken = await getAccessToken(request);
|
|
309
|
+
* if (!accessToken) {
|
|
310
|
+
* throw redirect('/login');
|
|
311
|
+
* }
|
|
312
|
+
*
|
|
313
|
+
* const response = await fetch('https://api.example.com/data', {
|
|
314
|
+
* headers: { Authorization: `Bearer ${accessToken}` },
|
|
315
|
+
* });
|
|
316
|
+
* return json(await response.json());
|
|
317
|
+
* }
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
async function getAccessToken(request, config, storage) {
|
|
321
|
+
const session = await getSession(request, storage);
|
|
322
|
+
const refreshToken = session.get('refreshToken');
|
|
323
|
+
if (!refreshToken) {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
const clientId = config?.clientId ?? process.env.COGNITO_CLIENT_ID;
|
|
327
|
+
if (!clientId) {
|
|
328
|
+
throw new Error('COGNITO_CLIENT_ID environment variable is required');
|
|
329
|
+
}
|
|
330
|
+
try {
|
|
331
|
+
const result = await (0, token_refresh_js_1.refreshAccessToken)(refreshToken, {
|
|
332
|
+
clientId,
|
|
333
|
+
region: config?.region,
|
|
334
|
+
});
|
|
335
|
+
return result.accessToken;
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
// Refresh token may be expired or invalid
|
|
339
|
+
console.error('Failed to refresh access token:', error);
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
290
343
|
//# sourceMappingURL=session.server.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.server.js","sourceRoot":"","sources":["../../src/remix/session.server.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;
|
|
1
|
+
{"version":3,"file":"session.server.js","sourceRoot":"","sources":["../../src/remix/session.server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fnd-platform/cognito-auth",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.4",
|
|
4
4
|
"description": "AWS Cognito authentication constructs and middleware for fnd-platform applications",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"lib/"
|
|
9
9
|
],
|
|
10
|
-
"scripts": {
|
|
11
|
-
"build": "tsc",
|
|
12
|
-
"test": "vitest run",
|
|
13
|
-
"test:watch": "vitest",
|
|
14
|
-
"test:coverage": "vitest run --coverage",
|
|
15
|
-
"lint": "eslint src/ test/"
|
|
16
|
-
},
|
|
17
10
|
"dependencies": {
|
|
18
11
|
"aws-jwt-verify": "^4.0.0"
|
|
19
12
|
},
|
|
@@ -66,5 +59,12 @@
|
|
|
66
59
|
"type": "git",
|
|
67
60
|
"url": "https://github.com/your-org/fnd-platform",
|
|
68
61
|
"directory": "packages/cognito-auth"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsc",
|
|
65
|
+
"test": "vitest run",
|
|
66
|
+
"test:watch": "vitest",
|
|
67
|
+
"test:coverage": "vitest run --coverage",
|
|
68
|
+
"lint": "eslint src/ test/"
|
|
69
69
|
}
|
|
70
|
-
}
|
|
70
|
+
}
|