@dotpress/auth 1.3.2 → 2.0.0-alpha.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.
- package/LICENSE +1 -1
- package/README.md +355 -329
- package/dist/index.d.ts +679 -8
- package/dist/index.js +1226 -20
- package/dist/index.js.map +1 -0
- package/package.json +32 -46
- package/dist/__tests__/functional/cookies.test.d.ts +0 -1
- package/dist/__tests__/functional/cookies.test.js +0 -621
- package/dist/__tests__/functional/handlers.test.d.ts +0 -1
- package/dist/__tests__/functional/handlers.test.js +0 -239
- package/dist/__tests__/functional/middlewares.test.d.ts +0 -1
- package/dist/__tests__/functional/middlewares.test.js +0 -111
- package/dist/__tests__/unit/cookies.test.d.ts +0 -1
- package/dist/__tests__/unit/cookies.test.js +0 -466
- package/dist/__tests__/unit/tokens.test.d.ts +0 -1
- package/dist/__tests__/unit/tokens.test.js +0 -225
- package/dist/lib/cookies.d.ts +0 -42
- package/dist/lib/cookies.js +0 -136
- package/dist/lib/generators.d.ts +0 -1
- package/dist/lib/generators.js +0 -4
- package/dist/lib/handlers.d.ts +0 -2
- package/dist/lib/handlers.js +0 -263
- package/dist/lib/ip.d.ts +0 -2
- package/dist/lib/ip.js +0 -15
- package/dist/lib/middleware.d.ts +0 -2
- package/dist/lib/middleware.js +0 -23
- package/dist/lib/settings.d.ts +0 -3
- package/dist/lib/settings.js +0 -42
- package/dist/lib/tokens.d.ts +0 -38
- package/dist/lib/tokens.js +0 -112
- package/dist/types/types.d.ts +0 -107
- package/dist/types/types.js +0 -1
package/dist/lib/cookies.d.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { Response, Request } from 'express';
|
|
2
|
-
import type { CookieSettings, AuthMode } from '../types/types.js';
|
|
3
|
-
type ResolvedCookieSettings = Required<Omit<CookieSettings, 'domain'>> & {
|
|
4
|
-
domain?: string;
|
|
5
|
-
};
|
|
6
|
-
export declare const getCookieSettings: () => ResolvedCookieSettings;
|
|
7
|
-
/**
|
|
8
|
-
* Set authentication cookies on the response
|
|
9
|
-
*/
|
|
10
|
-
export declare const setAuthCookies: (res: Response, tokens: {
|
|
11
|
-
accessToken: string;
|
|
12
|
-
refreshToken: string;
|
|
13
|
-
}, expiresInSeconds: number) => void;
|
|
14
|
-
/**
|
|
15
|
-
* Clear authentication cookies
|
|
16
|
-
*/
|
|
17
|
-
export declare const clearAuthCookies: (res: Response) => void;
|
|
18
|
-
/**
|
|
19
|
-
* Detect authentication mode from request
|
|
20
|
-
* Priority: cookies first, then body
|
|
21
|
-
*/
|
|
22
|
-
export declare const detectAuthMode: (req: Request) => AuthMode | null;
|
|
23
|
-
/**
|
|
24
|
-
* Extract tokens from request based on detected mode
|
|
25
|
-
*/
|
|
26
|
-
export declare const extractTokensFromRequest: (req: Request) => {
|
|
27
|
-
accessToken: string;
|
|
28
|
-
refreshToken: string;
|
|
29
|
-
} | null;
|
|
30
|
-
/**
|
|
31
|
-
* Extract access token from request
|
|
32
|
-
* Priority: Authorization header > cookie > body
|
|
33
|
-
*/
|
|
34
|
-
export declare const extractAccessToken: (req: Request) => string | null;
|
|
35
|
-
/**
|
|
36
|
-
* Calculate expiration timestamp
|
|
37
|
-
*/
|
|
38
|
-
export declare const calculateExpiration: (expiresInSeconds: number) => {
|
|
39
|
-
expiresIn: number;
|
|
40
|
-
expiresAt: string;
|
|
41
|
-
};
|
|
42
|
-
export {};
|
package/dist/lib/cookies.js
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { getSettings } from './settings.js';
|
|
2
|
-
const DEFAULT_COOKIE_SETTINGS = {
|
|
3
|
-
enabled: false,
|
|
4
|
-
httpOnly: true,
|
|
5
|
-
secure: process.env.NODE_ENV === 'production',
|
|
6
|
-
sameSite: 'lax',
|
|
7
|
-
path: '/',
|
|
8
|
-
accessTokenName: 'dotpress_access_token',
|
|
9
|
-
refreshTokenName: 'dotpress_refresh_token',
|
|
10
|
-
accessTokenInCookie: false,
|
|
11
|
-
domain: undefined,
|
|
12
|
-
};
|
|
13
|
-
export const getCookieSettings = () => {
|
|
14
|
-
const settings = getSettings();
|
|
15
|
-
return {
|
|
16
|
-
...DEFAULT_COOKIE_SETTINGS,
|
|
17
|
-
...settings.cookies,
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
/**
|
|
21
|
-
* Set authentication cookies on the response
|
|
22
|
-
*/
|
|
23
|
-
export const setAuthCookies = (res, tokens, expiresInSeconds) => {
|
|
24
|
-
const cookieSettings = getCookieSettings();
|
|
25
|
-
if (!cookieSettings.enabled) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const cookieOptions = {
|
|
29
|
-
httpOnly: cookieSettings.httpOnly,
|
|
30
|
-
secure: cookieSettings.secure,
|
|
31
|
-
sameSite: cookieSettings.sameSite,
|
|
32
|
-
path: cookieSettings.path,
|
|
33
|
-
domain: cookieSettings.domain,
|
|
34
|
-
maxAge: expiresInSeconds * 1000,
|
|
35
|
-
};
|
|
36
|
-
// Always set refresh token in cookie for 'cookie' mode
|
|
37
|
-
res.cookie(cookieSettings.refreshTokenName, tokens.refreshToken, cookieOptions);
|
|
38
|
-
// Optionally set access token in cookie
|
|
39
|
-
if (cookieSettings.accessTokenInCookie) {
|
|
40
|
-
res.cookie(cookieSettings.accessTokenName, tokens.accessToken, cookieOptions);
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
/**
|
|
44
|
-
* Clear authentication cookies
|
|
45
|
-
*/
|
|
46
|
-
export const clearAuthCookies = (res) => {
|
|
47
|
-
const cookieSettings = getCookieSettings();
|
|
48
|
-
if (!cookieSettings.enabled) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const cookieOptions = {
|
|
52
|
-
httpOnly: cookieSettings.httpOnly,
|
|
53
|
-
secure: cookieSettings.secure,
|
|
54
|
-
sameSite: cookieSettings.sameSite,
|
|
55
|
-
path: cookieSettings.path,
|
|
56
|
-
domain: cookieSettings.domain,
|
|
57
|
-
};
|
|
58
|
-
res.clearCookie(cookieSettings.refreshTokenName, cookieOptions);
|
|
59
|
-
if (cookieSettings.accessTokenInCookie) {
|
|
60
|
-
res.clearCookie(cookieSettings.accessTokenName, cookieOptions);
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Detect authentication mode from request
|
|
65
|
-
* Priority: cookies first, then body
|
|
66
|
-
*/
|
|
67
|
-
export const detectAuthMode = (req) => {
|
|
68
|
-
const cookieSettings = getCookieSettings();
|
|
69
|
-
// Check if refresh token exists in cookies
|
|
70
|
-
if (req.cookies?.[cookieSettings.refreshTokenName]) {
|
|
71
|
-
return 'cookie';
|
|
72
|
-
}
|
|
73
|
-
// Check if refresh token exists in body
|
|
74
|
-
if (req.body?.refreshToken) {
|
|
75
|
-
return 'body';
|
|
76
|
-
}
|
|
77
|
-
return null;
|
|
78
|
-
};
|
|
79
|
-
/**
|
|
80
|
-
* Extract tokens from request based on detected mode
|
|
81
|
-
*/
|
|
82
|
-
export const extractTokensFromRequest = (req) => {
|
|
83
|
-
const mode = detectAuthMode(req);
|
|
84
|
-
const cookieSettings = getCookieSettings();
|
|
85
|
-
if (mode === 'cookie') {
|
|
86
|
-
const refreshToken = req.cookies?.[cookieSettings.refreshTokenName];
|
|
87
|
-
const accessToken = cookieSettings.accessTokenInCookie
|
|
88
|
-
? req.cookies?.[cookieSettings.accessTokenName]
|
|
89
|
-
: req.body?.accessToken;
|
|
90
|
-
if (!refreshToken || !accessToken) {
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
return { accessToken, refreshToken };
|
|
94
|
-
}
|
|
95
|
-
if (mode === 'body') {
|
|
96
|
-
const { accessToken, refreshToken } = req.body || {};
|
|
97
|
-
if (!accessToken || !refreshToken) {
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
return { accessToken, refreshToken };
|
|
101
|
-
}
|
|
102
|
-
return null;
|
|
103
|
-
};
|
|
104
|
-
/**
|
|
105
|
-
* Extract access token from request
|
|
106
|
-
* Priority: Authorization header > cookie > body
|
|
107
|
-
*/
|
|
108
|
-
export const extractAccessToken = (req) => {
|
|
109
|
-
// Priority 1: Authorization header
|
|
110
|
-
const authHeader = req.headers.authorization;
|
|
111
|
-
if (authHeader?.startsWith('Bearer ')) {
|
|
112
|
-
return authHeader.replace('Bearer ', '');
|
|
113
|
-
}
|
|
114
|
-
const cookieSettings = getCookieSettings();
|
|
115
|
-
// Priority 2: Cookie (if enabled)
|
|
116
|
-
if (cookieSettings.enabled &&
|
|
117
|
-
cookieSettings.accessTokenInCookie &&
|
|
118
|
-
req.cookies?.[cookieSettings.accessTokenName]) {
|
|
119
|
-
return req.cookies[cookieSettings.accessTokenName];
|
|
120
|
-
}
|
|
121
|
-
// Priority 3: Body
|
|
122
|
-
if (req.body?.accessToken) {
|
|
123
|
-
return req.body.accessToken;
|
|
124
|
-
}
|
|
125
|
-
return null;
|
|
126
|
-
};
|
|
127
|
-
/**
|
|
128
|
-
* Calculate expiration timestamp
|
|
129
|
-
*/
|
|
130
|
-
export const calculateExpiration = (expiresInSeconds) => {
|
|
131
|
-
const expiresAt = new Date(Date.now() + expiresInSeconds * 1000);
|
|
132
|
-
return {
|
|
133
|
-
expiresIn: expiresInSeconds,
|
|
134
|
-
expiresAt: expiresAt.toISOString(),
|
|
135
|
-
};
|
|
136
|
-
};
|
package/dist/lib/generators.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const generateUUID: () => `${string}-${string}-${string}-${string}-${string}`;
|
package/dist/lib/generators.js
DELETED
package/dist/lib/handlers.d.ts
DELETED
package/dist/lib/handlers.js
DELETED
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
import { unauthorizedError, internalError } from 'dotpress';
|
|
2
|
-
import bcrypt from 'bcryptjs';
|
|
3
|
-
import { getSettings } from './settings.js';
|
|
4
|
-
import { getRequestIp } from './ip.js';
|
|
5
|
-
import { generateTokensForUser, generateTokensFromRefreshToken, validateAndDecodeAccessToken, } from './tokens.js';
|
|
6
|
-
import { setAuthCookies, clearAuthCookies, extractTokensFromRequest, calculateExpiration, getCookieSettings, } from './cookies.js';
|
|
7
|
-
export const registerHandlers = (plugin) => {
|
|
8
|
-
const authGroup = plugin.addGroup('/auth');
|
|
9
|
-
const settings = getSettings();
|
|
10
|
-
authGroup.defineRoute({
|
|
11
|
-
method: 'post',
|
|
12
|
-
path: '/login',
|
|
13
|
-
schema: (z) => ({
|
|
14
|
-
body: z.object({
|
|
15
|
-
username: z.string(),
|
|
16
|
-
password: z.string(),
|
|
17
|
-
client: z.string().optional(),
|
|
18
|
-
aud: settings.aud?.required ? z.string() : z.string().optional(),
|
|
19
|
-
mode: z.enum(['body', 'cookie']).optional(),
|
|
20
|
-
}),
|
|
21
|
-
response: z.object({
|
|
22
|
-
userId: z.string(),
|
|
23
|
-
accessToken: z.string(),
|
|
24
|
-
refreshToken: z.string(),
|
|
25
|
-
expiresIn: z.number(),
|
|
26
|
-
expiresAt: z.string(),
|
|
27
|
-
}),
|
|
28
|
-
}),
|
|
29
|
-
handler: async ({ req, res }) => {
|
|
30
|
-
const { username, password, client, aud, mode } = req.body;
|
|
31
|
-
const ipAddress = getRequestIp(req);
|
|
32
|
-
const user = await settings.dataProvider.findUserIdentifiers(username);
|
|
33
|
-
if (!user) {
|
|
34
|
-
if (settings.onLoginFailed) {
|
|
35
|
-
await settings.onLoginFailed({
|
|
36
|
-
username,
|
|
37
|
-
errorType: 'invalid_username',
|
|
38
|
-
client: client || '',
|
|
39
|
-
ipAddress: ipAddress || '',
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
return unauthorizedError('INVALID_LOGIN');
|
|
43
|
-
}
|
|
44
|
-
const isPasswordValid = await bcrypt.compare(password, user.passwordHash);
|
|
45
|
-
if (!isPasswordValid) {
|
|
46
|
-
if (settings.onLoginFailed) {
|
|
47
|
-
await settings.onLoginFailed({
|
|
48
|
-
username,
|
|
49
|
-
errorType: 'invalid_password',
|
|
50
|
-
client: client || '',
|
|
51
|
-
ipAddress: ipAddress || '',
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
return unauthorizedError('INVALID_LOGIN');
|
|
55
|
-
}
|
|
56
|
-
if (aud && typeof settings.aud?.isUserRoleAllowed === 'function') {
|
|
57
|
-
const isAllowed = settings.aud.isUserRoleAllowed(user.role || '', aud);
|
|
58
|
-
if (!isAllowed) {
|
|
59
|
-
if (settings.onLoginFailed) {
|
|
60
|
-
await settings.onLoginFailed({
|
|
61
|
-
username,
|
|
62
|
-
errorType: 'invalid_role',
|
|
63
|
-
client: client || '',
|
|
64
|
-
ipAddress: ipAddress || '',
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
return unauthorizedError('INVALID_LOGIN');
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
const { accessToken, refreshToken } = await generateTokensForUser({
|
|
71
|
-
username,
|
|
72
|
-
userId: user.userId,
|
|
73
|
-
aud,
|
|
74
|
-
});
|
|
75
|
-
if (settings.onLoginSuccess) {
|
|
76
|
-
await settings.onLoginSuccess({
|
|
77
|
-
userId: user.userId,
|
|
78
|
-
username,
|
|
79
|
-
client: client || '',
|
|
80
|
-
ipAddress: ipAddress || '',
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
if (mode === 'cookie') {
|
|
84
|
-
setAuthCookies(res, { accessToken, refreshToken }, settings.refreshTokenTTLInDays * 24 * 60 * 60);
|
|
85
|
-
}
|
|
86
|
-
const expiration = calculateExpiration(settings.accessTokenTTL);
|
|
87
|
-
return {
|
|
88
|
-
userId: user.userId,
|
|
89
|
-
accessToken,
|
|
90
|
-
refreshToken,
|
|
91
|
-
...expiration,
|
|
92
|
-
};
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
authGroup.defineRoute({
|
|
96
|
-
method: 'post',
|
|
97
|
-
path: '/refresh',
|
|
98
|
-
schema: (z) => ({
|
|
99
|
-
body: z
|
|
100
|
-
.object({
|
|
101
|
-
accessToken: z.string().optional(),
|
|
102
|
-
refreshToken: z.string().optional(),
|
|
103
|
-
})
|
|
104
|
-
.optional(),
|
|
105
|
-
response: z.object({
|
|
106
|
-
userId: z.string(),
|
|
107
|
-
accessToken: z.string(),
|
|
108
|
-
refreshToken: z.string(),
|
|
109
|
-
expiresIn: z.number(),
|
|
110
|
-
expiresAt: z.string(),
|
|
111
|
-
}),
|
|
112
|
-
}),
|
|
113
|
-
handler: async ({ req, res }) => {
|
|
114
|
-
// Extract tokens from cookies or body (auto-detect)
|
|
115
|
-
const extractedTokens = extractTokensFromRequest(req);
|
|
116
|
-
if (!extractedTokens) {
|
|
117
|
-
return unauthorizedError('NO_TOKENS_PROVIDED');
|
|
118
|
-
}
|
|
119
|
-
const { accessToken, refreshToken } = extractedTokens;
|
|
120
|
-
try {
|
|
121
|
-
const tokens = await generateTokensFromRefreshToken({
|
|
122
|
-
accessToken,
|
|
123
|
-
refreshToken,
|
|
124
|
-
});
|
|
125
|
-
// Set cookies if the request came with cookies (auto-detect mode)
|
|
126
|
-
const mode = req.cookies?.[settings.cookies?.refreshTokenName || 'dotpress_refresh_token']
|
|
127
|
-
? 'cookie'
|
|
128
|
-
: 'body';
|
|
129
|
-
if (mode === 'cookie') {
|
|
130
|
-
setAuthCookies(res, {
|
|
131
|
-
accessToken: tokens.accessToken,
|
|
132
|
-
refreshToken: tokens.refreshToken,
|
|
133
|
-
}, settings.refreshTokenTTLInDays * 24 * 60 * 60);
|
|
134
|
-
}
|
|
135
|
-
const expiration = calculateExpiration(settings.accessTokenTTL);
|
|
136
|
-
return {
|
|
137
|
-
userId: tokens.userId,
|
|
138
|
-
accessToken: tokens.accessToken,
|
|
139
|
-
refreshToken: tokens.refreshToken,
|
|
140
|
-
...expiration,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
catch (e) {
|
|
144
|
-
const errorMessage = e.message;
|
|
145
|
-
if (errorMessage === 'Invalid_Refresh_Token') {
|
|
146
|
-
return unauthorizedError('INVALID_REFRESH_TOKEN');
|
|
147
|
-
}
|
|
148
|
-
if (errorMessage === 'Expired_Refresh_Token') {
|
|
149
|
-
return unauthorizedError('EXPIRED_REFRESH_TOKEN');
|
|
150
|
-
}
|
|
151
|
-
return internalError('Can not refresh tokens.');
|
|
152
|
-
}
|
|
153
|
-
},
|
|
154
|
-
});
|
|
155
|
-
authGroup.defineRoute({
|
|
156
|
-
method: 'get',
|
|
157
|
-
path: '/me',
|
|
158
|
-
handler: async ({ req }) => {
|
|
159
|
-
if (!req.user) {
|
|
160
|
-
return unauthorizedError();
|
|
161
|
-
}
|
|
162
|
-
return req.user;
|
|
163
|
-
},
|
|
164
|
-
});
|
|
165
|
-
authGroup.defineRoute({
|
|
166
|
-
method: 'post',
|
|
167
|
-
path: '/restore',
|
|
168
|
-
schema: (z) => ({
|
|
169
|
-
response: z.object({
|
|
170
|
-
userId: z.string(),
|
|
171
|
-
accessToken: z.string(),
|
|
172
|
-
refreshToken: z.string(),
|
|
173
|
-
expiresIn: z.number(),
|
|
174
|
-
expiresAt: z.string(),
|
|
175
|
-
user: z.unknown(),
|
|
176
|
-
}),
|
|
177
|
-
}),
|
|
178
|
-
handler: async ({ req, res }) => {
|
|
179
|
-
const cookieSettings = getCookieSettings();
|
|
180
|
-
// Only support cookie mode for restore
|
|
181
|
-
if (!cookieSettings.enabled) {
|
|
182
|
-
return unauthorizedError('COOKIES_NOT_ENABLED');
|
|
183
|
-
}
|
|
184
|
-
// This endpoint requires accessTokenInCookie to be enabled
|
|
185
|
-
if (!cookieSettings.accessTokenInCookie) {
|
|
186
|
-
return unauthorizedError('ACCESS_TOKEN_NOT_IN_COOKIE');
|
|
187
|
-
}
|
|
188
|
-
const refreshToken = req.cookies?.[cookieSettings.refreshTokenName];
|
|
189
|
-
const accessToken = req.cookies?.[cookieSettings.accessTokenName];
|
|
190
|
-
if (!refreshToken) {
|
|
191
|
-
return unauthorizedError('NO_REFRESH_TOKEN');
|
|
192
|
-
}
|
|
193
|
-
if (!accessToken) {
|
|
194
|
-
return unauthorizedError('NO_ACCESS_TOKEN');
|
|
195
|
-
}
|
|
196
|
-
// Try to validate access token first
|
|
197
|
-
try {
|
|
198
|
-
const { userId } = validateAndDecodeAccessToken(accessToken);
|
|
199
|
-
const user = await settings.dataProvider.findUserById(userId);
|
|
200
|
-
if (user) {
|
|
201
|
-
const expiration = calculateExpiration(settings.accessTokenTTL);
|
|
202
|
-
return {
|
|
203
|
-
userId,
|
|
204
|
-
accessToken,
|
|
205
|
-
refreshToken,
|
|
206
|
-
...expiration,
|
|
207
|
-
user,
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
catch {
|
|
212
|
-
// Access token is invalid or expired, continue to refresh logic
|
|
213
|
-
}
|
|
214
|
-
// Access token is expired, try to refresh using refresh token
|
|
215
|
-
try {
|
|
216
|
-
const tokens = await generateTokensFromRefreshToken({
|
|
217
|
-
accessToken,
|
|
218
|
-
refreshToken,
|
|
219
|
-
});
|
|
220
|
-
// Set new cookies
|
|
221
|
-
setAuthCookies(res, {
|
|
222
|
-
accessToken: tokens.accessToken,
|
|
223
|
-
refreshToken: tokens.refreshToken,
|
|
224
|
-
}, settings.refreshTokenTTLInDays * 24 * 60 * 60);
|
|
225
|
-
const user = await settings.dataProvider.findUserById(tokens.userId);
|
|
226
|
-
if (!user) {
|
|
227
|
-
return unauthorizedError('USER_NOT_FOUND');
|
|
228
|
-
}
|
|
229
|
-
const expiration = calculateExpiration(settings.accessTokenTTL);
|
|
230
|
-
return {
|
|
231
|
-
userId: tokens.userId,
|
|
232
|
-
accessToken: tokens.accessToken,
|
|
233
|
-
refreshToken: tokens.refreshToken,
|
|
234
|
-
...expiration,
|
|
235
|
-
user,
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
catch (e) {
|
|
239
|
-
const errorMessage = e.message;
|
|
240
|
-
if (errorMessage === 'Invalid_Refresh_Token') {
|
|
241
|
-
return unauthorizedError('INVALID_REFRESH_TOKEN');
|
|
242
|
-
}
|
|
243
|
-
if (errorMessage === 'Expired_Refresh_Token') {
|
|
244
|
-
return unauthorizedError('EXPIRED_REFRESH_TOKEN');
|
|
245
|
-
}
|
|
246
|
-
return internalError('Cannot restore session.');
|
|
247
|
-
}
|
|
248
|
-
},
|
|
249
|
-
});
|
|
250
|
-
authGroup.defineRoute({
|
|
251
|
-
method: 'post',
|
|
252
|
-
path: '/logout',
|
|
253
|
-
handler: async ({ req, res }) => {
|
|
254
|
-
const userId = req.user?.id || '';
|
|
255
|
-
if (!userId) {
|
|
256
|
-
return unauthorizedError();
|
|
257
|
-
}
|
|
258
|
-
await settings.dataProvider.revokeTokens(userId);
|
|
259
|
-
clearAuthCookies(res);
|
|
260
|
-
return { success: true };
|
|
261
|
-
},
|
|
262
|
-
});
|
|
263
|
-
};
|
package/dist/lib/ip.d.ts
DELETED
package/dist/lib/ip.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import requestIp from 'request-ip';
|
|
2
|
-
export const getRequestIp = (req) => {
|
|
3
|
-
const clientIp = requestIp.getClientIp(req);
|
|
4
|
-
const localIps = [
|
|
5
|
-
'127.0.0.1',
|
|
6
|
-
'localhost',
|
|
7
|
-
'::1',
|
|
8
|
-
'::ffff',
|
|
9
|
-
'::ffff:127.0.0.1',
|
|
10
|
-
];
|
|
11
|
-
if (clientIp && localIps.includes(clientIp)) {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
return clientIp;
|
|
15
|
-
};
|
package/dist/lib/middleware.d.ts
DELETED
package/dist/lib/middleware.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { getSettings } from './settings.js';
|
|
2
|
-
import { validateAndDecodeAccessToken } from './tokens.js';
|
|
3
|
-
import { extractAccessToken } from './cookies.js';
|
|
4
|
-
export const attachAuthenticatedUser = async (req, _res, next) => {
|
|
5
|
-
const accessToken = extractAccessToken(req);
|
|
6
|
-
if (!accessToken) {
|
|
7
|
-
next();
|
|
8
|
-
return;
|
|
9
|
-
}
|
|
10
|
-
try {
|
|
11
|
-
const settings = getSettings();
|
|
12
|
-
const { userId } = validateAndDecodeAccessToken(accessToken);
|
|
13
|
-
const user = await settings.dataProvider.findUserById(userId);
|
|
14
|
-
if (user) {
|
|
15
|
-
req.user = user;
|
|
16
|
-
}
|
|
17
|
-
next();
|
|
18
|
-
}
|
|
19
|
-
catch (e) {
|
|
20
|
-
console.warn(e);
|
|
21
|
-
next();
|
|
22
|
-
}
|
|
23
|
-
};
|
package/dist/lib/settings.d.ts
DELETED
package/dist/lib/settings.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
let pluginSettings = {
|
|
2
|
-
accessTokenTTL: 3600,
|
|
3
|
-
refreshTokenTTLInDays: 14,
|
|
4
|
-
issuer: '',
|
|
5
|
-
keys: {
|
|
6
|
-
secretKey: '',
|
|
7
|
-
publicKey: '',
|
|
8
|
-
},
|
|
9
|
-
dataProvider: {
|
|
10
|
-
storeRefreshToken: () => {
|
|
11
|
-
throw new Error('storeRefreshToken() is not implemented.');
|
|
12
|
-
},
|
|
13
|
-
findRefreshToken: () => {
|
|
14
|
-
throw new Error('findRefreshToken() is not implemented.');
|
|
15
|
-
},
|
|
16
|
-
markRefreshTokenAsUsed: () => {
|
|
17
|
-
throw new Error('markRefreshTokenAsUsed() is not implemented.');
|
|
18
|
-
},
|
|
19
|
-
revokeTokens: () => {
|
|
20
|
-
throw new Error('revokeTokens() is not implemented.');
|
|
21
|
-
},
|
|
22
|
-
findUserById: () => {
|
|
23
|
-
throw new Error('findUserById() is not implemented.');
|
|
24
|
-
},
|
|
25
|
-
findUserIdentifiers: () => {
|
|
26
|
-
throw new Error('findUserByUsername() is not implemented.');
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
onLoginFailed: () => {
|
|
30
|
-
return Promise.resolve();
|
|
31
|
-
},
|
|
32
|
-
onLoginSuccess: () => {
|
|
33
|
-
return Promise.resolve();
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
export const setSettings = (settings) => {
|
|
37
|
-
pluginSettings = {
|
|
38
|
-
...pluginSettings,
|
|
39
|
-
...settings,
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
export const getSettings = () => pluginSettings;
|
package/dist/lib/tokens.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { TokenPair } from '../types/types.js';
|
|
2
|
-
type CreateTokenPayload = {
|
|
3
|
-
sub: string;
|
|
4
|
-
username: string;
|
|
5
|
-
auth_time: number;
|
|
6
|
-
aud?: string;
|
|
7
|
-
};
|
|
8
|
-
type CreatedAccessToken = {
|
|
9
|
-
jwtId: string;
|
|
10
|
-
accessToken: string;
|
|
11
|
-
};
|
|
12
|
-
type CreatedRefreshToken = {
|
|
13
|
-
token: string;
|
|
14
|
-
tokenHash: string;
|
|
15
|
-
};
|
|
16
|
-
type UserIdentifiers = {
|
|
17
|
-
userId: string;
|
|
18
|
-
username: string;
|
|
19
|
-
aud?: string;
|
|
20
|
-
};
|
|
21
|
-
export declare const createAccessTokenFromPayload: (payload: CreateTokenPayload) => CreatedAccessToken;
|
|
22
|
-
export declare const generateRefreshToken: () => CreatedRefreshToken;
|
|
23
|
-
/**
|
|
24
|
-
* Generate a pair of access and refresh tokens for a given user
|
|
25
|
-
*/
|
|
26
|
-
export declare const generateTokensForUser: ({ userId, username, aud, }: UserIdentifiers) => Promise<TokenPair>;
|
|
27
|
-
export declare const generateAccessToken: ({ userId, username, aud, }: UserIdentifiers) => CreatedAccessToken;
|
|
28
|
-
/**
|
|
29
|
-
* Regenerate a pair of token using a refresh token
|
|
30
|
-
* Expired access token must be provided in order to validate userId and jwtId
|
|
31
|
-
*/
|
|
32
|
-
export declare const generateTokensFromRefreshToken: ({ accessToken, refreshToken, }: TokenPair) => Promise<TokenPair & {
|
|
33
|
-
userId: string;
|
|
34
|
-
}>;
|
|
35
|
-
export declare const validateAndDecodeAccessToken: (accessToken: string) => {
|
|
36
|
-
userId: string;
|
|
37
|
-
};
|
|
38
|
-
export {};
|