@thinkingcat/auth-utils 1.0.50 → 2.0.1
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/dist/core/auth-response.d.ts +15 -0
- package/dist/core/auth-response.js +45 -0
- package/dist/core/cookies.d.ts +33 -0
- package/dist/core/cookies.js +102 -0
- package/dist/core/jwt.d.ts +28 -0
- package/dist/core/jwt.js +180 -0
- package/dist/core/roles.d.ts +25 -0
- package/dist/core/roles.js +62 -0
- package/dist/core/verify.d.ts +40 -0
- package/dist/core/verify.js +181 -0
- package/dist/index.d.ts +18 -634
- package/dist/index.js +34 -1642
- package/dist/middleware/config.d.ts +15 -0
- package/dist/middleware/config.js +38 -0
- package/dist/middleware/handler.d.ts +6 -0
- package/dist/middleware/handler.js +228 -0
- package/dist/nextauth/callbacks.d.ts +35 -0
- package/dist/nextauth/callbacks.js +143 -0
- package/dist/nextauth/config.d.ts +50 -0
- package/dist/nextauth/config.js +66 -0
- package/dist/nextauth/session.d.ts +10 -0
- package/dist/nextauth/session.js +40 -0
- package/dist/sso/api.d.ts +23 -0
- package/dist/sso/api.js +83 -0
- package/dist/types/index.d.ts +138 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/crypto.d.ts +4 -0
- package/dist/utils/crypto.js +13 -0
- package/dist/utils/license.d.ts +4 -0
- package/dist/utils/license.js +20 -0
- package/dist/utils/logger.d.ts +5 -0
- package/dist/utils/logger.js +17 -0
- package/dist/utils/path.d.ts +12 -0
- package/dist/utils/path.js +25 -0
- package/dist/utils/redirect.d.ts +17 -0
- package/dist/utils/redirect.js +50 -0
- package/dist/utils/server.d.ts +8 -0
- package/dist/utils/server.js +42 -0
- package/package.json +6 -4
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verifyAndRefreshToken = verifyAndRefreshToken;
|
|
4
|
+
exports.verifyAndRefreshTokenWithNextAuth = verifyAndRefreshTokenWithNextAuth;
|
|
5
|
+
const jose_1 = require("jose");
|
|
6
|
+
const logger_1 = require("../utils/logger");
|
|
7
|
+
const api_1 = require("../sso/api");
|
|
8
|
+
const server_1 = require("../utils/server");
|
|
9
|
+
const jwt_1 = require("./jwt");
|
|
10
|
+
const cookies_1 = require("./cookies");
|
|
11
|
+
/**
|
|
12
|
+
* 토큰 검증 및 갱신 시도
|
|
13
|
+
*/
|
|
14
|
+
async function verifyAndRefreshToken(req, secret, options) {
|
|
15
|
+
const { cookiePrefix, serviceId, isProduction, cookieDomain, ssoBaseURL, authServiceKey, forceRefresh = false, } = options;
|
|
16
|
+
const accessTokenName = `${cookiePrefix}_access_token`;
|
|
17
|
+
const accessToken = req.cookies.get(accessTokenName)?.value;
|
|
18
|
+
if (accessToken && !forceRefresh) {
|
|
19
|
+
try {
|
|
20
|
+
const secretBytes = new TextEncoder().encode(secret);
|
|
21
|
+
const { payload } = await (0, jose_1.jwtVerify)(accessToken, secretBytes);
|
|
22
|
+
if (payload && typeof payload === 'object' && payload.email) {
|
|
23
|
+
return { isValid: true, payload: payload };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Token verification failed
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const refreshTokenName = `${cookiePrefix}_refresh_token`;
|
|
31
|
+
const refreshToken = req.cookies.get(refreshTokenName)?.value;
|
|
32
|
+
if (refreshToken) {
|
|
33
|
+
try {
|
|
34
|
+
if (!ssoBaseURL || !authServiceKey) {
|
|
35
|
+
return { isValid: false, error: 'SSO_CONFIG_MISSING' };
|
|
36
|
+
}
|
|
37
|
+
const refreshResult = await (0, api_1.refreshSSOToken)(refreshToken, {
|
|
38
|
+
ssoBaseURL,
|
|
39
|
+
authServiceKey,
|
|
40
|
+
});
|
|
41
|
+
if (refreshResult.success && refreshResult.accessToken) {
|
|
42
|
+
const newRefreshToken = refreshResult.refreshToken || refreshToken;
|
|
43
|
+
try {
|
|
44
|
+
let payload;
|
|
45
|
+
const secretBytes = new TextEncoder().encode(secret);
|
|
46
|
+
const { payload: tokenPayload } = await (0, jose_1.jwtVerify)(refreshResult.accessToken, secretBytes);
|
|
47
|
+
if (tokenPayload && typeof tokenPayload === 'object' && tokenPayload.email) {
|
|
48
|
+
payload = tokenPayload;
|
|
49
|
+
}
|
|
50
|
+
const { NextResponse: NextResponseClass } = await (0, server_1.getNextServer)();
|
|
51
|
+
const response = NextResponseClass.next();
|
|
52
|
+
const jwt = (0, jwt_1.createNextAuthJWT)(payload, serviceId);
|
|
53
|
+
if (newRefreshToken)
|
|
54
|
+
jwt.refreshToken = newRefreshToken;
|
|
55
|
+
jwt.accessTokenExpires = Date.now() + (15 * 60 * 1000);
|
|
56
|
+
try {
|
|
57
|
+
const encodedSessionToken = await (0, jwt_1.encodeNextAuthToken)(jwt, secret, 30 * 24 * 60 * 60);
|
|
58
|
+
(0, cookies_1.setNextAuthToken)(response, encodedSessionToken, {
|
|
59
|
+
isProduction,
|
|
60
|
+
cookieDomain,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
(0, logger_1.debugError)('verifyAndRefreshToken', 'Failed to set NextAuth session cookie', error);
|
|
65
|
+
}
|
|
66
|
+
if (newRefreshToken) {
|
|
67
|
+
(0, cookies_1.setCustomTokens)(response, refreshResult.accessToken, newRefreshToken, {
|
|
68
|
+
cookiePrefix,
|
|
69
|
+
isProduction,
|
|
70
|
+
cookieDomain,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
(0, cookies_1.setCustomTokens)(response, refreshResult.accessToken, {
|
|
75
|
+
cookiePrefix,
|
|
76
|
+
isProduction,
|
|
77
|
+
cookieDomain,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return { isValid: true, response, payload };
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
return { isValid: false, error: 'SESSION_CREATION_FAILED' };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
const { NextResponse: NextResponseClass } = await (0, server_1.getNextServer)();
|
|
88
|
+
const response = NextResponseClass.next();
|
|
89
|
+
(0, cookies_1.clearAllAuthCookies)(response, options.cookiePrefix, options.isProduction);
|
|
90
|
+
return { isValid: false, response, error: 'REFRESH_FAILED' };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
const { NextResponse: NextResponseClass } = await (0, server_1.getNextServer)();
|
|
95
|
+
const response = NextResponseClass.next();
|
|
96
|
+
(0, cookies_1.clearAllAuthCookies)(response, options.cookiePrefix, options.isProduction);
|
|
97
|
+
return { isValid: false, response, error: 'REFRESH_ERROR' };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return { isValid: false, error: 'NO_TOKEN' };
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* NextAuth 토큰과 자체 토큰을 모두 확인하는 미들웨어용 함수
|
|
104
|
+
*/
|
|
105
|
+
async function verifyAndRefreshTokenWithNextAuth(req, nextAuthToken, secret, options) {
|
|
106
|
+
const { cookiePrefix, isProduction } = options;
|
|
107
|
+
const nextAuthSessionTokenCookieName = isProduction
|
|
108
|
+
? '__Secure-next-auth.session-token'
|
|
109
|
+
: 'next-auth.session-token';
|
|
110
|
+
const nextAuthCookieValue = req.cookies.get(nextAuthSessionTokenCookieName)?.value;
|
|
111
|
+
const hasNextAuthSessionTokenCookie = !!nextAuthCookieValue;
|
|
112
|
+
const hasValidNextAuthToken = nextAuthToken && (0, jwt_1.isValidToken)(nextAuthToken);
|
|
113
|
+
const accessTokenName = `${cookiePrefix}_access_token`;
|
|
114
|
+
const accessToken = req.cookies.get(accessTokenName)?.value;
|
|
115
|
+
let hasValidAccessToken = false;
|
|
116
|
+
if (accessToken) {
|
|
117
|
+
try {
|
|
118
|
+
const secretBytes = new TextEncoder().encode(secret);
|
|
119
|
+
const { payload } = await (0, jose_1.jwtVerify)(accessToken, secretBytes);
|
|
120
|
+
if (payload && typeof payload === 'object' && payload.email) {
|
|
121
|
+
hasValidAccessToken = true;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Ignored
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const refreshTokenName = `${cookiePrefix}_refresh_token`;
|
|
129
|
+
const refreshToken = req.cookies.get(refreshTokenName)?.value;
|
|
130
|
+
if (hasValidNextAuthToken && hasValidAccessToken) {
|
|
131
|
+
let payload;
|
|
132
|
+
if (accessToken) {
|
|
133
|
+
try {
|
|
134
|
+
const secretBytes = new TextEncoder().encode(secret);
|
|
135
|
+
const result = await (0, jose_1.jwtVerify)(accessToken, secretBytes);
|
|
136
|
+
payload = result.payload;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// Ignored
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
isValid: true,
|
|
144
|
+
token: nextAuthToken,
|
|
145
|
+
payload
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (refreshToken && (!hasValidNextAuthToken || !hasValidAccessToken)) {
|
|
149
|
+
const authCheck = await verifyAndRefreshToken(req, secret, {
|
|
150
|
+
...options,
|
|
151
|
+
forceRefresh: true,
|
|
152
|
+
});
|
|
153
|
+
let refreshedToken = null;
|
|
154
|
+
if (authCheck.isValid && authCheck.payload) {
|
|
155
|
+
refreshedToken = (0, jwt_1.createNextAuthJWT)(authCheck.payload, options.serviceId);
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
...authCheck,
|
|
159
|
+
token: refreshedToken || undefined
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (hasValidNextAuthToken || hasValidAccessToken) {
|
|
163
|
+
let payload;
|
|
164
|
+
if (accessToken && hasValidAccessToken) {
|
|
165
|
+
try {
|
|
166
|
+
const secretBytes = new TextEncoder().encode(secret);
|
|
167
|
+
const result = await (0, jose_1.jwtVerify)(accessToken, secretBytes);
|
|
168
|
+
payload = result.payload;
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// Ignored
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
isValid: true,
|
|
176
|
+
token: nextAuthToken || (payload ? (0, jwt_1.createNextAuthJWT)(payload, options.serviceId) : undefined),
|
|
177
|
+
payload
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return { isValid: false, error: 'NO_TOKEN' };
|
|
181
|
+
}
|