nuxt-auther 1.0.2 → 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.
- package/dist/module.cjs +5 -0
- package/dist/module.d.mts +3 -0
- package/dist/module.d.ts +3 -0
- package/dist/module.json +8 -0
- package/dist/module.mjs +1007 -0
- package/dist/runtime/composables.d.ts +2 -0
- package/dist/runtime/composables.mjs +2 -0
- package/dist/runtime/core/auth.d.ts +53 -0
- package/dist/runtime/core/auth.mjs +387 -0
- package/dist/runtime/core/index.d.ts +3 -0
- package/dist/runtime/core/index.mjs +3 -0
- package/dist/runtime/core/middleware.d.ts +2 -0
- package/dist/runtime/core/middleware.mjs +41 -0
- package/dist/runtime/core/storage.d.ts +41 -0
- package/dist/runtime/core/storage.mjs +277 -0
- package/dist/runtime/inc/configuration-document-request-error.d.ts +3 -0
- package/dist/runtime/inc/configuration-document-request-error.mjs +6 -0
- package/dist/runtime/inc/configuration-document.d.ts +26 -0
- package/dist/runtime/inc/configuration-document.mjs +94 -0
- package/dist/runtime/inc/default-properties.d.ts +123 -0
- package/dist/runtime/inc/default-properties.mjs +132 -0
- package/dist/runtime/inc/expired-auth-session-error.d.ts +3 -0
- package/dist/runtime/inc/expired-auth-session-error.mjs +6 -0
- package/dist/runtime/inc/id-token.d.ts +15 -0
- package/dist/runtime/inc/id-token.mjs +81 -0
- package/dist/runtime/inc/index.d.ts +10 -0
- package/dist/runtime/inc/index.mjs +10 -0
- package/dist/runtime/inc/refresh-controller.d.ts +9 -0
- package/dist/runtime/inc/refresh-controller.mjs +29 -0
- package/dist/runtime/inc/refresh-token.d.ts +14 -0
- package/dist/runtime/inc/refresh-token.mjs +75 -0
- package/dist/runtime/inc/request-handler.d.ts +17 -0
- package/dist/runtime/inc/request-handler.mjs +93 -0
- package/dist/runtime/inc/token-status.d.ts +12 -0
- package/dist/runtime/inc/token-status.mjs +39 -0
- package/dist/runtime/inc/token.d.ts +14 -0
- package/dist/runtime/inc/token.mjs +83 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.mjs +3 -0
- package/dist/runtime/providers/auth0.d.ts +7 -0
- package/dist/runtime/providers/auth0.mjs +15 -0
- package/dist/runtime/providers/discord.d.ts +6 -0
- package/dist/runtime/providers/discord.mjs +18 -0
- package/dist/runtime/providers/facebook.d.ts +6 -0
- package/dist/runtime/providers/facebook.mjs +13 -0
- package/dist/runtime/providers/github.d.ts +6 -0
- package/dist/runtime/providers/github.mjs +15 -0
- package/dist/runtime/providers/google.d.ts +6 -0
- package/dist/runtime/providers/google.mjs +13 -0
- package/dist/runtime/providers/index.d.ts +8 -0
- package/dist/runtime/providers/index.mjs +8 -0
- package/dist/runtime/providers/laravel-jwt.d.ts +7 -0
- package/dist/runtime/providers/laravel-jwt.mjs +47 -0
- package/dist/runtime/providers/laravel-passport.d.ts +12 -0
- package/dist/runtime/providers/laravel-passport.mjs +69 -0
- package/dist/runtime/providers/laravel-sanctum.d.ts +6 -0
- package/dist/runtime/providers/laravel-sanctum.mjs +52 -0
- package/dist/runtime/schemes/auth0.d.ts +4 -0
- package/dist/runtime/schemes/auth0.mjs +13 -0
- package/dist/runtime/schemes/base.d.ts +8 -0
- package/dist/runtime/schemes/base.mjs +11 -0
- package/dist/runtime/schemes/cookie.d.ts +23 -0
- package/dist/runtime/schemes/cookie.mjs +111 -0
- package/dist/runtime/schemes/index.d.ts +8 -0
- package/dist/runtime/schemes/index.mjs +8 -0
- package/dist/runtime/schemes/laravel-jwt.d.ts +5 -0
- package/dist/runtime/schemes/laravel-jwt.mjs +6 -0
- package/dist/runtime/schemes/local.d.ts +38 -0
- package/dist/runtime/schemes/local.mjs +160 -0
- package/dist/runtime/schemes/oauth2.d.ts +61 -0
- package/dist/runtime/schemes/oauth2.mjs +374 -0
- package/dist/runtime/schemes/openIDConnect.d.ts +24 -0
- package/dist/runtime/schemes/openIDConnect.mjs +190 -0
- package/dist/runtime/schemes/refresh.d.ts +26 -0
- package/dist/runtime/schemes/refresh.mjs +141 -0
- package/dist/runtime/token-nitro.d.ts +2 -0
- package/dist/runtime/token-nitro.mjs +9 -0
- package/dist/types/index.d.ts +42 -0
- package/dist/types/openIDConnectConfigurationDocument.d.ts +31 -0
- package/dist/types/options.d.ts +125 -0
- package/dist/types/provider.d.ts +21 -0
- package/dist/types/request.d.ts +8 -0
- package/dist/types/router.d.ts +7 -0
- package/dist/types/scheme.d.ts +108 -0
- package/dist/types/store.d.ts +30 -0
- package/dist/types/strategy.d.ts +16 -0
- package/dist/types/utils.d.ts +5 -0
- package/dist/utils/index.d.ts +28 -0
- package/dist/utils/index.mjs +123 -0
- package/dist/utils/provider.d.ts +13 -0
- package/dist/utils/provider.mjs +360 -0
- package/package.json +5 -3
package/dist/module.mjs
ADDED
|
@@ -0,0 +1,1007 @@
|
|
|
1
|
+
import { addTemplate, addServerHandler, resolvePath, defineNuxtModule, createResolver, installModule, addPluginTemplate, addImports, addRouteMiddleware } from '@nuxt/kit';
|
|
2
|
+
import { serialize } from '@refactorjs/serialize';
|
|
3
|
+
import { join } from 'pathe';
|
|
4
|
+
import { defu } from 'defu';
|
|
5
|
+
import 'jwt-decode';
|
|
6
|
+
import { existsSync } from 'fs';
|
|
7
|
+
import { hash } from 'ohash';
|
|
8
|
+
|
|
9
|
+
const name = "nuxt-auther";
|
|
10
|
+
const version = "1.0.4";
|
|
11
|
+
|
|
12
|
+
const OAUTH2DEFAULTS = {
|
|
13
|
+
accessType: void 0,
|
|
14
|
+
redirectUri: void 0,
|
|
15
|
+
logoutRedirectUri: void 0,
|
|
16
|
+
clientId: void 0,
|
|
17
|
+
clientSecretTransport: "body",
|
|
18
|
+
audience: void 0,
|
|
19
|
+
grantType: void 0,
|
|
20
|
+
responseMode: void 0,
|
|
21
|
+
acrValues: void 0,
|
|
22
|
+
autoLogout: false,
|
|
23
|
+
endpoints: {
|
|
24
|
+
logout: void 0,
|
|
25
|
+
authorization: void 0,
|
|
26
|
+
token: void 0,
|
|
27
|
+
userInfo: void 0
|
|
28
|
+
},
|
|
29
|
+
scope: [],
|
|
30
|
+
token: {
|
|
31
|
+
property: "access_token",
|
|
32
|
+
expiresProperty: "expires_in",
|
|
33
|
+
type: "Bearer",
|
|
34
|
+
name: "Authorization",
|
|
35
|
+
maxAge: false,
|
|
36
|
+
global: true,
|
|
37
|
+
prefix: "_token.",
|
|
38
|
+
expirationPrefix: "_token_expiration."
|
|
39
|
+
},
|
|
40
|
+
idToken: {
|
|
41
|
+
property: "id_token",
|
|
42
|
+
maxAge: 1800,
|
|
43
|
+
prefix: "_id_token.",
|
|
44
|
+
expirationPrefix: "_id_token_expiration.",
|
|
45
|
+
httpOnly: false
|
|
46
|
+
},
|
|
47
|
+
refreshToken: {
|
|
48
|
+
property: "refresh_token",
|
|
49
|
+
maxAge: 60 * 60 * 24 * 30,
|
|
50
|
+
prefix: "_refresh_token.",
|
|
51
|
+
expirationPrefix: "_refresh_token_expiration.",
|
|
52
|
+
httpOnly: false
|
|
53
|
+
},
|
|
54
|
+
user: {
|
|
55
|
+
property: false
|
|
56
|
+
},
|
|
57
|
+
responseType: "token",
|
|
58
|
+
codeChallengeMethod: false,
|
|
59
|
+
clientWindow: false,
|
|
60
|
+
clientWindowWidth: 400,
|
|
61
|
+
clientWindowHeight: 600
|
|
62
|
+
};
|
|
63
|
+
const LOCALDEFAULTS = {
|
|
64
|
+
cookie: {
|
|
65
|
+
name: void 0
|
|
66
|
+
},
|
|
67
|
+
endpoints: {
|
|
68
|
+
csrf: {
|
|
69
|
+
url: "/api/csrf-cookie"
|
|
70
|
+
},
|
|
71
|
+
login: {
|
|
72
|
+
url: "/api/auth/login",
|
|
73
|
+
method: "post"
|
|
74
|
+
},
|
|
75
|
+
logout: {
|
|
76
|
+
url: "/api/auth/logout",
|
|
77
|
+
method: "post"
|
|
78
|
+
},
|
|
79
|
+
user: {
|
|
80
|
+
url: "/api/auth/user",
|
|
81
|
+
method: "get"
|
|
82
|
+
},
|
|
83
|
+
refresh: {
|
|
84
|
+
url: "/api/auth/refresh",
|
|
85
|
+
method: "post"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
token: {
|
|
89
|
+
expiresProperty: "expires_in",
|
|
90
|
+
property: "token",
|
|
91
|
+
type: "Bearer",
|
|
92
|
+
name: "Authorization",
|
|
93
|
+
maxAge: false,
|
|
94
|
+
global: true,
|
|
95
|
+
required: true,
|
|
96
|
+
prefix: "_token.",
|
|
97
|
+
expirationPrefix: "_token_expiration.",
|
|
98
|
+
httpOnly: false
|
|
99
|
+
},
|
|
100
|
+
refreshToken: {
|
|
101
|
+
property: "refresh_token",
|
|
102
|
+
data: "refresh_token",
|
|
103
|
+
maxAge: 60 * 60 * 24 * 30,
|
|
104
|
+
required: true,
|
|
105
|
+
tokenRequired: false,
|
|
106
|
+
prefix: "_refresh_token.",
|
|
107
|
+
expirationPrefix: "_refresh_token_expiration.",
|
|
108
|
+
httpOnly: false
|
|
109
|
+
},
|
|
110
|
+
autoLogout: false,
|
|
111
|
+
user: {
|
|
112
|
+
property: "user",
|
|
113
|
+
autoFetch: true
|
|
114
|
+
},
|
|
115
|
+
clientId: void 0,
|
|
116
|
+
grantType: void 0,
|
|
117
|
+
scope: void 0
|
|
118
|
+
};
|
|
119
|
+
const ProviderAliases = {
|
|
120
|
+
"laravel/jwt": "laravelJWT",
|
|
121
|
+
"laravel/passport": "laravelPassport",
|
|
122
|
+
"laravel/sanctum": "laravelSanctum"
|
|
123
|
+
};
|
|
124
|
+
const BuiltinSchemes = {
|
|
125
|
+
local: "LocalScheme",
|
|
126
|
+
cookie: "CookieScheme",
|
|
127
|
+
refresh: "RefreshScheme",
|
|
128
|
+
laravelJWT: "LaravelJWTScheme",
|
|
129
|
+
oauth2: "Oauth2Scheme",
|
|
130
|
+
openIDConnect: "OpenIDConnectScheme",
|
|
131
|
+
auth0: "Auth0Scheme"
|
|
132
|
+
};
|
|
133
|
+
const LocalSchemes = [
|
|
134
|
+
"local",
|
|
135
|
+
"cookie",
|
|
136
|
+
"refresh",
|
|
137
|
+
"laravelJWT"
|
|
138
|
+
];
|
|
139
|
+
const OAuth2Schemes = [
|
|
140
|
+
"oauth",
|
|
141
|
+
"openIDConnect",
|
|
142
|
+
"auth0"
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
function assignDefaults(strategy, defaults) {
|
|
146
|
+
Object.assign(strategy, defu(strategy, defaults));
|
|
147
|
+
}
|
|
148
|
+
function addAuthorize(nuxt, strategy, useForms = false) {
|
|
149
|
+
const clientSecret = strategy.clientSecret;
|
|
150
|
+
const clientId = strategy.clientId;
|
|
151
|
+
const tokenEndpoint = strategy.endpoints.token;
|
|
152
|
+
const audience = strategy.audience;
|
|
153
|
+
delete strategy.clientSecret;
|
|
154
|
+
const endpoint = `/_auth/oauth/${strategy.name}/authorize`;
|
|
155
|
+
strategy.endpoints.token = endpoint;
|
|
156
|
+
strategy.responseType = "code";
|
|
157
|
+
addTemplate({
|
|
158
|
+
filename: `authorize-${strategy.name}.ts`,
|
|
159
|
+
write: true,
|
|
160
|
+
getContents: () => authorizeGrant({
|
|
161
|
+
strategy,
|
|
162
|
+
useForms,
|
|
163
|
+
clientSecret,
|
|
164
|
+
clientId,
|
|
165
|
+
tokenEndpoint,
|
|
166
|
+
audience
|
|
167
|
+
})
|
|
168
|
+
});
|
|
169
|
+
addServerHandler({
|
|
170
|
+
route: endpoint,
|
|
171
|
+
method: "post",
|
|
172
|
+
handler: join(nuxt.options.buildDir, `authorize-${strategy.name}.ts`)
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
function addLocalAuthorize(nuxt, strategy) {
|
|
176
|
+
const tokenEndpoint = strategy.endpoints?.login?.url;
|
|
177
|
+
const refreshEndpoint = strategy.endpoints?.refresh?.url;
|
|
178
|
+
const endpoint = `/_auth/local/${strategy.name}/authorize`;
|
|
179
|
+
strategy.endpoints.login.url = endpoint;
|
|
180
|
+
strategy.endpoints.refresh.url = endpoint;
|
|
181
|
+
addTemplate({
|
|
182
|
+
filename: `local-${strategy.name}.ts`,
|
|
183
|
+
write: true,
|
|
184
|
+
getContents: () => localAuthorizeGrant({
|
|
185
|
+
strategy,
|
|
186
|
+
tokenEndpoint,
|
|
187
|
+
refreshEndpoint
|
|
188
|
+
})
|
|
189
|
+
});
|
|
190
|
+
addServerHandler({
|
|
191
|
+
route: endpoint,
|
|
192
|
+
method: "post",
|
|
193
|
+
handler: join(nuxt.options.buildDir, `local-${strategy.name}.ts`)
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
function initializePasswordGrantFlow(nuxt, strategy) {
|
|
197
|
+
const clientSecret = strategy.clientSecret;
|
|
198
|
+
const clientId = strategy.clientId;
|
|
199
|
+
const tokenEndpoint = strategy.endpoints.token;
|
|
200
|
+
delete strategy.clientSecret;
|
|
201
|
+
const endpoint = `/_auth/${strategy.name}/token`;
|
|
202
|
+
strategy.endpoints.login.url = endpoint;
|
|
203
|
+
strategy.endpoints.refresh.url = endpoint;
|
|
204
|
+
addTemplate({
|
|
205
|
+
filename: `password-${strategy.name}.ts`,
|
|
206
|
+
write: true,
|
|
207
|
+
getContents: () => passwordGrant({
|
|
208
|
+
strategy,
|
|
209
|
+
clientSecret,
|
|
210
|
+
clientId,
|
|
211
|
+
tokenEndpoint
|
|
212
|
+
})
|
|
213
|
+
});
|
|
214
|
+
addServerHandler({
|
|
215
|
+
route: endpoint,
|
|
216
|
+
method: "post",
|
|
217
|
+
handler: join(nuxt.options.buildDir, `password-${strategy.name}.ts`)
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
function assignAbsoluteEndpoints(strategy) {
|
|
221
|
+
const { url, endpoints } = strategy;
|
|
222
|
+
if (endpoints) {
|
|
223
|
+
for (const key of Object.keys(endpoints)) {
|
|
224
|
+
const endpoint = endpoints[key];
|
|
225
|
+
if (endpoint) {
|
|
226
|
+
if (typeof endpoint === "object") {
|
|
227
|
+
if (!endpoint.url || endpoint.url.startsWith(url)) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
endpoints[key].url = url + endpoint.url;
|
|
231
|
+
} else {
|
|
232
|
+
if (endpoint.startsWith(url)) {
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
endpoints[key] = url + endpoint;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function authorizeGrant(opt) {
|
|
242
|
+
return `import { defineEventHandler, readBody, createError, getCookie } from 'h3'
|
|
243
|
+
// @ts-expect-error: virtual file
|
|
244
|
+
import { config } from '#nuxt-auth-options'
|
|
245
|
+
import { serialize } from 'cookie-es'
|
|
246
|
+
|
|
247
|
+
const options = ${serialize(opt, { space: 4 })}
|
|
248
|
+
|
|
249
|
+
function addTokenPrefix(token: string | boolean, tokenType: string | false): string | boolean {
|
|
250
|
+
if (!token || !tokenType || typeof token !== 'string' || token.startsWith(tokenType)) {
|
|
251
|
+
return token;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return tokenType + ' ' + token;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export default defineEventHandler(async (event) => {
|
|
258
|
+
const {
|
|
259
|
+
code,
|
|
260
|
+
code_verifier: codeVerifier,
|
|
261
|
+
redirect_uri: redirectUri = options.strategy.redirectUri,
|
|
262
|
+
response_type: responseType = options.strategy.responseType,
|
|
263
|
+
grant_type: grantType = options.strategy.grantType,
|
|
264
|
+
refresh_token: refreshToken
|
|
265
|
+
} = await readBody(event)
|
|
266
|
+
|
|
267
|
+
const refreshCookieName = config.stores.cookie.prefix + options.strategy?.refreshToken?.prefix + options.strategy.name
|
|
268
|
+
const tokenCookieName = config.stores.cookie.prefix + options.strategy?.token?.prefix + options.strategy.name
|
|
269
|
+
const idTokenCookieName = config.stores.cookie.prefix + options.strategy?.idToken?.prefix + options.strategy.name
|
|
270
|
+
const serverRefreshToken = getCookie(event, refreshCookieName)
|
|
271
|
+
|
|
272
|
+
// Grant type is authorization code, but code is not available
|
|
273
|
+
if (grantType === 'authorization_code' && !code) {
|
|
274
|
+
return createError({
|
|
275
|
+
statusCode: 500,
|
|
276
|
+
message: 'Missing authorization code'
|
|
277
|
+
})
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Grant type is refresh token, but refresh token is not available
|
|
281
|
+
if ((grantType === 'refresh_token' && !options.strategy.refreshToken.httpOnly && !refreshToken) || (grantType === 'refresh_token' && options.strategy.refreshToken.httpOnly && !serverRefreshToken)) {
|
|
282
|
+
return createError({
|
|
283
|
+
statusCode: 500,
|
|
284
|
+
message: 'Missing refresh token'
|
|
285
|
+
})
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
let body = {
|
|
289
|
+
client_id: options.clientId,
|
|
290
|
+
client_secret: options.clientSecret,
|
|
291
|
+
refresh_token: options.strategy.refreshToken.httpOnly ? serverRefreshToken : refreshToken,
|
|
292
|
+
grant_type: grantType,
|
|
293
|
+
response_type: responseType,
|
|
294
|
+
redirect_uri: redirectUri,
|
|
295
|
+
audience: options.audience,
|
|
296
|
+
code_verifier: codeVerifier,
|
|
297
|
+
code
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (grantType !== 'refresh_token') {
|
|
301
|
+
delete body.refresh_token
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const headers = {
|
|
305
|
+
Accept: 'application/json',
|
|
306
|
+
'Content-Type': 'application/json'
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (options.strategy.clientSecretTransport === 'authorization_header') {
|
|
310
|
+
// @ts-ignore
|
|
311
|
+
headers['Authorization'] = 'Basic ' + Buffer.from(options.clientId + ':' + options.clientSecret).toString('base64')
|
|
312
|
+
// client_secret is transported in auth header
|
|
313
|
+
delete body.client_secret
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const response = await $http.post(options.tokenEndpoint, {
|
|
317
|
+
body,
|
|
318
|
+
headers
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
let cookies = event.node.res.getHeader('Set-Cookie') as string[] || [];
|
|
322
|
+
|
|
323
|
+
const refreshCookieValue = response._data?.[options.strategy?.refreshToken?.property]
|
|
324
|
+
if (config.stores.cookie.enabled && refreshCookieValue && options.strategy.refreshToken.httpOnly) {
|
|
325
|
+
const refreshCookie = serialize(refreshCookieName, refreshCookieValue, { ...config.stores.cookie.options, httpOnly: true })
|
|
326
|
+
cookies.push(refreshCookie);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const tokenCookieValue = response._data?.[options.strategy?.token?.property]
|
|
330
|
+
if (config.stores.cookie.enabled && tokenCookieValue && options.strategy.token.httpOnly) {
|
|
331
|
+
const token = addTokenPrefix(tokenCookieValue, options.strategy.token.type) as string
|
|
332
|
+
const tokenCookie = serialize(tokenCookieName, token, { ...config.stores.cookie.options, httpOnly: true })
|
|
333
|
+
cookies.push(tokenCookie);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const idTokenCookieValue = response._data?.[options.strategy?.idToken?.property]
|
|
337
|
+
if (config.stores.cookie.enabled && idTokenCookieValue && options.strategy.idToken.httpOnly) {
|
|
338
|
+
const idTokenCookie = serialize(idTokenCookieName, token, { ...config.stores.cookie.options, httpOnly: true })
|
|
339
|
+
cookies.push(idTokenCookie);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (cookies.length) {
|
|
343
|
+
event.node.res.setHeader('Set-Cookie', cookies);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
event.node.res.end(JSON.stringify(response._data))
|
|
347
|
+
})
|
|
348
|
+
`;
|
|
349
|
+
}
|
|
350
|
+
function localAuthorizeGrant(opt) {
|
|
351
|
+
return `import { defineEventHandler, readBody, createError, getCookie, getRequestHeader } from 'h3'
|
|
352
|
+
// @ts-expect-error: virtual file
|
|
353
|
+
import { config } from '#nuxt-auth-options'
|
|
354
|
+
import { serialize } from 'cookie-es'
|
|
355
|
+
|
|
356
|
+
const options = ${serialize(opt, { space: 4 })}
|
|
357
|
+
|
|
358
|
+
function addTokenPrefix(token: string | boolean, tokenType: string | false): string | boolean {
|
|
359
|
+
if (!token || !tokenType || typeof token !== 'string' || token.startsWith(tokenType)) {
|
|
360
|
+
return token;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return tokenType + ' ' + token;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export default defineEventHandler(async (event) => {
|
|
367
|
+
const requestBody = await readBody(event)
|
|
368
|
+
|
|
369
|
+
const refreshCookieName = config.stores.cookie.prefix + options.strategy?.refreshToken?.prefix + options.strategy.name
|
|
370
|
+
const refreshTokenDataName = options.strategy.refreshToken.data
|
|
371
|
+
const tokenCookieName = config.stores.cookie.prefix + options.strategy?.token?.prefix + options.strategy.name
|
|
372
|
+
const serverRefreshToken = getCookie(event, refreshCookieName)
|
|
373
|
+
const authHeader = getRequestHeader(event, 'authorization')
|
|
374
|
+
|
|
375
|
+
// Grant type is refresh token, but refresh token is not available
|
|
376
|
+
if ((requestBody.grant_type === 'refresh_token' && !options.strategy.refreshToken.httpOnly && !requestBody[refreshTokenDataName]) || (requestBody.grant_type === 'refresh_token' && options.strategy.refreshToken.httpOnly && !serverRefreshToken)) {
|
|
377
|
+
return createError({
|
|
378
|
+
statusCode: 500,
|
|
379
|
+
message: 'Missing refresh token'
|
|
380
|
+
})
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
let body = {
|
|
384
|
+
...requestBody,
|
|
385
|
+
[refreshTokenDataName]: options.strategy.refreshToken.httpOnly ? serverRefreshToken : requestBody[refreshTokenDataName],
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (requestBody.grant_type !== 'refresh_token') {
|
|
389
|
+
delete body[refreshTokenDataName]
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
let headers = {
|
|
393
|
+
'Content-Type': 'application/json'
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
let response
|
|
397
|
+
|
|
398
|
+
if (body[refreshTokenDataName]) {
|
|
399
|
+
if (options.strategy?.refreshToken?.tokenRequired && authHeader) {
|
|
400
|
+
headers = {
|
|
401
|
+
...headers,
|
|
402
|
+
// @ts-ignore
|
|
403
|
+
Authorization: authHeader,
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
response = await $http.post(options.refreshEndpoint, {
|
|
408
|
+
body,
|
|
409
|
+
headers: {
|
|
410
|
+
...headers,
|
|
411
|
+
// @ts-ignore: headers might not be set
|
|
412
|
+
...options.strategy?.endpoints?.refresh?.headers
|
|
413
|
+
}
|
|
414
|
+
})
|
|
415
|
+
} else {
|
|
416
|
+
response = await $http.post(options.tokenEndpoint, {
|
|
417
|
+
body,
|
|
418
|
+
headers: {
|
|
419
|
+
...headers,
|
|
420
|
+
// @ts-ignore: headers might not be set
|
|
421
|
+
...options.strategy?.endpoints?.login?.headers
|
|
422
|
+
}
|
|
423
|
+
})
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
let cookies = event.node.res.getHeader('Set-Cookie') as string[] || [];
|
|
427
|
+
|
|
428
|
+
const refreshCookieValue = response._data?.[options.strategy?.refreshToken?.property]
|
|
429
|
+
if (config.stores.cookie.enabled && refreshCookieValue && options.strategy.refreshToken.httpOnly) {
|
|
430
|
+
const refreshCookie = serialize(refreshCookieName, refreshCookieValue, { ...config.stores.cookie.options, httpOnly: true })
|
|
431
|
+
cookies.push(refreshCookie);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const tokenCookieValue = response._data?.[options.strategy?.token?.property]
|
|
435
|
+
if (config.stores.cookie.enabled && tokenCookieValue && options.strategy.token.httpOnly) {
|
|
436
|
+
const token = addTokenPrefix(tokenCookieValue, options.strategy.token.type) as string
|
|
437
|
+
const tokenCookie = serialize(tokenCookieName, token, { ...config.stores.cookie.options, httpOnly: true })
|
|
438
|
+
cookies.push(tokenCookie);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (cookies.length) {
|
|
442
|
+
event.node.res.setHeader('Set-Cookie', cookies);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
event.node.res.end(JSON.stringify(response._data))
|
|
446
|
+
})
|
|
447
|
+
`;
|
|
448
|
+
}
|
|
449
|
+
function passwordGrant(opt) {
|
|
450
|
+
return `import requrl from 'requrl';
|
|
451
|
+
import { defineEventHandler, readBody, createError } from 'h3';
|
|
452
|
+
|
|
453
|
+
const options = ${serialize(opt, { space: 4 })}
|
|
454
|
+
|
|
455
|
+
export default defineEventHandler(async (event) => {
|
|
456
|
+
const body = await readBody(event)
|
|
457
|
+
|
|
458
|
+
// If \`grant_type\` is not defined, set default value
|
|
459
|
+
if (!body.grant_type) {
|
|
460
|
+
body.grant_type = options.strategy.grantType
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// If \`client_id\` is not defined, set default value
|
|
464
|
+
if (!body.client_id) {
|
|
465
|
+
body.grant_type = options.clientId
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Grant type is password, but username or password is not available
|
|
469
|
+
if (body.grant_type === 'password' && (!body.username || !body.password)) {
|
|
470
|
+
return createError({
|
|
471
|
+
statusCode: 400,
|
|
472
|
+
message: 'Invalid username or password'
|
|
473
|
+
})
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Grant type is refresh token, but refresh token is not available
|
|
477
|
+
if (body.grant_type === 'refresh_token' && !body.refresh_token) {
|
|
478
|
+
event.respondWith({ status: 400, body: JSON.stringify({ message: 'Refresh token not provided' }) });
|
|
479
|
+
return createError({
|
|
480
|
+
statusCode: 400,
|
|
481
|
+
message: 'Refresh token not provided'
|
|
482
|
+
})
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const response = await $http.post(options.tokenEndpoint, {
|
|
486
|
+
baseURL: requrl(event.node.req),
|
|
487
|
+
body: {
|
|
488
|
+
client_id: options.clientId,
|
|
489
|
+
client_secret: options.clientSecret,
|
|
490
|
+
...body
|
|
491
|
+
},
|
|
492
|
+
headers: {
|
|
493
|
+
Accept: 'application/json'
|
|
494
|
+
}
|
|
495
|
+
})
|
|
496
|
+
|
|
497
|
+
event.node.res.end(JSON.stringify(response._data))
|
|
498
|
+
})
|
|
499
|
+
`;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const hasOwn = (object, key) => Object.hasOwn ? Object.hasOwn(object, key) : Object.prototype.hasOwnProperty.call(object, key);
|
|
503
|
+
|
|
504
|
+
function auth0(nuxt, strategy) {
|
|
505
|
+
const DEFAULTS = Object.assign(OAUTH2DEFAULTS, {
|
|
506
|
+
scheme: "auth0",
|
|
507
|
+
endpoints: {
|
|
508
|
+
authorization: `https://${strategy.domain}/authorize`,
|
|
509
|
+
userInfo: `https://${strategy.domain}/userinfo`,
|
|
510
|
+
token: `https://${strategy.domain}/oauth/token`,
|
|
511
|
+
logout: `https://${strategy.domain}/v2/logout`
|
|
512
|
+
},
|
|
513
|
+
scope: ["openid", "profile", "email"]
|
|
514
|
+
});
|
|
515
|
+
assignDefaults(strategy, DEFAULTS);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
function discord(nuxt, strategy) {
|
|
519
|
+
const DEFAULTS = Object.assign(OAUTH2DEFAULTS, {
|
|
520
|
+
scheme: "oauth2",
|
|
521
|
+
endpoints: {
|
|
522
|
+
authorization: "https://discord.com/api/oauth2/authorize",
|
|
523
|
+
token: "https://discord.com/api/oauth2/token",
|
|
524
|
+
userInfo: "https://discord.com/api/users/@me"
|
|
525
|
+
// logout: 'https://discord.com/api/oauth2/token/revoke' //TODO: add post method, because discord using the post method to logout
|
|
526
|
+
},
|
|
527
|
+
grantType: "authorization_code",
|
|
528
|
+
codeChallengeMethod: "S256",
|
|
529
|
+
scope: ["identify", "email"]
|
|
530
|
+
});
|
|
531
|
+
assignDefaults(strategy, DEFAULTS);
|
|
532
|
+
addAuthorize(nuxt, strategy, true);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function facebook(nuxt, strategy) {
|
|
536
|
+
const DEFAULTS = Object.assign(OAUTH2DEFAULTS, {
|
|
537
|
+
scheme: "oauth2",
|
|
538
|
+
endpoints: {
|
|
539
|
+
authorization: "https://facebook.com/v2.12/dialog/oauth",
|
|
540
|
+
userInfo: "https://graph.facebook.com/v2.12/me?fields=about,name,picture{url},email"
|
|
541
|
+
},
|
|
542
|
+
scope: ["public_profile", "email"]
|
|
543
|
+
});
|
|
544
|
+
assignDefaults(strategy, DEFAULTS);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function github(nuxt, strategy) {
|
|
548
|
+
const DEFAULTS = Object.assign(OAUTH2DEFAULTS, {
|
|
549
|
+
scheme: "oauth2",
|
|
550
|
+
endpoints: {
|
|
551
|
+
authorization: "https://github.com/login/oauth/authorize",
|
|
552
|
+
token: "https://github.com/login/oauth/access_token",
|
|
553
|
+
userInfo: "https://api.github.com/user"
|
|
554
|
+
},
|
|
555
|
+
scope: ["user", "email"]
|
|
556
|
+
});
|
|
557
|
+
assignDefaults(strategy, DEFAULTS);
|
|
558
|
+
addAuthorize(nuxt, strategy);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function google(nuxt, strategy) {
|
|
562
|
+
const DEFAULTS = Object.assign(OAUTH2DEFAULTS, {
|
|
563
|
+
scheme: "oauth2",
|
|
564
|
+
endpoints: {
|
|
565
|
+
authorization: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
566
|
+
userInfo: "https://www.googleapis.com/oauth2/v3/userinfo"
|
|
567
|
+
},
|
|
568
|
+
scope: ["openid", "profile", "email"]
|
|
569
|
+
});
|
|
570
|
+
assignDefaults(strategy, DEFAULTS);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function laravelJWT(nuxt, strategy) {
|
|
574
|
+
const { url } = strategy;
|
|
575
|
+
if (!url) {
|
|
576
|
+
throw new Error("url is required for laravel jwt!");
|
|
577
|
+
}
|
|
578
|
+
const DEFAULTS = Object.assign(LOCALDEFAULTS, {
|
|
579
|
+
name: "laravelJWT",
|
|
580
|
+
scheme: "laravelJWT",
|
|
581
|
+
endpoints: {
|
|
582
|
+
login: {
|
|
583
|
+
url: url + "/api/auth/login"
|
|
584
|
+
},
|
|
585
|
+
refresh: {
|
|
586
|
+
url: url + "/api/auth/refresh"
|
|
587
|
+
},
|
|
588
|
+
logout: {
|
|
589
|
+
url: url + "/api/auth/logout"
|
|
590
|
+
},
|
|
591
|
+
user: {
|
|
592
|
+
url: url + "/api/auth/user"
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
token: {
|
|
596
|
+
property: "access_token",
|
|
597
|
+
maxAge: 3600
|
|
598
|
+
},
|
|
599
|
+
refreshToken: {
|
|
600
|
+
property: false,
|
|
601
|
+
data: false,
|
|
602
|
+
maxAge: 1209600,
|
|
603
|
+
required: false,
|
|
604
|
+
tokenRequired: true
|
|
605
|
+
},
|
|
606
|
+
user: {
|
|
607
|
+
property: false
|
|
608
|
+
},
|
|
609
|
+
clientId: false,
|
|
610
|
+
grantType: false
|
|
611
|
+
});
|
|
612
|
+
assignDefaults(strategy, DEFAULTS);
|
|
613
|
+
assignAbsoluteEndpoints(strategy);
|
|
614
|
+
if (strategy.ssr) {
|
|
615
|
+
addLocalAuthorize(nuxt, strategy);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
function isPasswordGrant(strategy) {
|
|
620
|
+
return strategy.grantType === "password";
|
|
621
|
+
}
|
|
622
|
+
function laravelPassport(nuxt, strategy) {
|
|
623
|
+
const { url } = strategy;
|
|
624
|
+
if (!url) {
|
|
625
|
+
throw new Error("url is required is laravel passport!");
|
|
626
|
+
}
|
|
627
|
+
const defaults = Object.assign(LOCALDEFAULTS, {
|
|
628
|
+
name: "laravelPassport",
|
|
629
|
+
token: {
|
|
630
|
+
property: "access_token",
|
|
631
|
+
type: "Bearer",
|
|
632
|
+
name: "Authorization",
|
|
633
|
+
maxAge: 60 * 60 * 24 * 365
|
|
634
|
+
},
|
|
635
|
+
refreshToken: {
|
|
636
|
+
property: "refresh_token",
|
|
637
|
+
data: "refresh_token",
|
|
638
|
+
maxAge: 60 * 60 * 24 * 30
|
|
639
|
+
},
|
|
640
|
+
user: {
|
|
641
|
+
property: false
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
let DEFAULTS;
|
|
645
|
+
if (isPasswordGrant(strategy)) {
|
|
646
|
+
DEFAULTS = {
|
|
647
|
+
...defaults,
|
|
648
|
+
scheme: "refresh",
|
|
649
|
+
endpoints: {
|
|
650
|
+
token: url + "/oauth/token",
|
|
651
|
+
login: {
|
|
652
|
+
baseURL: ""
|
|
653
|
+
},
|
|
654
|
+
refresh: {
|
|
655
|
+
baseURL: ""
|
|
656
|
+
},
|
|
657
|
+
logout: false,
|
|
658
|
+
user: {
|
|
659
|
+
url: url + "/api/auth/user"
|
|
660
|
+
}
|
|
661
|
+
},
|
|
662
|
+
grantType: "password"
|
|
663
|
+
};
|
|
664
|
+
assignDefaults(strategy, DEFAULTS);
|
|
665
|
+
assignAbsoluteEndpoints(strategy);
|
|
666
|
+
initializePasswordGrantFlow(nuxt, strategy);
|
|
667
|
+
} else {
|
|
668
|
+
DEFAULTS = {
|
|
669
|
+
...defaults,
|
|
670
|
+
scheme: "oauth2",
|
|
671
|
+
endpoints: {
|
|
672
|
+
authorization: url + "/oauth/authorize",
|
|
673
|
+
token: url + "/oauth/token",
|
|
674
|
+
userInfo: url + "/api/auth/user",
|
|
675
|
+
logout: false
|
|
676
|
+
},
|
|
677
|
+
responseType: "code",
|
|
678
|
+
grantType: "authorization_code",
|
|
679
|
+
scope: "*"
|
|
680
|
+
};
|
|
681
|
+
assignDefaults(strategy, DEFAULTS);
|
|
682
|
+
assignAbsoluteEndpoints(strategy);
|
|
683
|
+
addAuthorize(nuxt, strategy);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
function laravelSanctum(nuxt, strategy) {
|
|
688
|
+
const { url } = strategy;
|
|
689
|
+
if (!url) {
|
|
690
|
+
throw new Error("URL is required with Laravel Sanctum!");
|
|
691
|
+
}
|
|
692
|
+
const endpointDefaults = {
|
|
693
|
+
credentials: "include"
|
|
694
|
+
};
|
|
695
|
+
const DEFAULTS = Object.assign(LOCALDEFAULTS, {
|
|
696
|
+
scheme: "cookie",
|
|
697
|
+
name: "laravelSanctum",
|
|
698
|
+
cookie: {
|
|
699
|
+
name: "XSRF-TOKEN"
|
|
700
|
+
},
|
|
701
|
+
endpoints: {
|
|
702
|
+
csrf: {
|
|
703
|
+
...endpointDefaults,
|
|
704
|
+
url: "/sanctum/csrf-cookie"
|
|
705
|
+
},
|
|
706
|
+
login: {
|
|
707
|
+
...endpointDefaults,
|
|
708
|
+
url: "/login"
|
|
709
|
+
},
|
|
710
|
+
refresh: {
|
|
711
|
+
...endpointDefaults,
|
|
712
|
+
url: "/refresh"
|
|
713
|
+
},
|
|
714
|
+
logout: {
|
|
715
|
+
...endpointDefaults,
|
|
716
|
+
url: "/logout"
|
|
717
|
+
},
|
|
718
|
+
user: {
|
|
719
|
+
...endpointDefaults,
|
|
720
|
+
url: "/api/user"
|
|
721
|
+
}
|
|
722
|
+
},
|
|
723
|
+
user: {
|
|
724
|
+
property: false,
|
|
725
|
+
autoFetch: true
|
|
726
|
+
},
|
|
727
|
+
token: {
|
|
728
|
+
type: "Bearer"
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
assignDefaults(strategy, DEFAULTS);
|
|
732
|
+
assignAbsoluteEndpoints(strategy);
|
|
733
|
+
if (strategy.ssr) {
|
|
734
|
+
addLocalAuthorize(nuxt, strategy);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const AUTH_PROVIDERS = {
|
|
739
|
+
__proto__: null,
|
|
740
|
+
auth0: auth0,
|
|
741
|
+
discord: discord,
|
|
742
|
+
facebook: facebook,
|
|
743
|
+
github: github,
|
|
744
|
+
google: google,
|
|
745
|
+
laravelJWT: laravelJWT,
|
|
746
|
+
laravelPassport: laravelPassport,
|
|
747
|
+
laravelSanctum: laravelSanctum
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
async function resolveStrategies(nuxt, options) {
|
|
751
|
+
const strategies = [];
|
|
752
|
+
const strategyScheme = {};
|
|
753
|
+
for (const name of Object.keys(options.strategies)) {
|
|
754
|
+
if (!options.strategies?.[name] || options.strategies?.[name].enabled === false) {
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
const strategy = Object.assign({}, options.strategies[name]);
|
|
758
|
+
if (!strategy.name) {
|
|
759
|
+
strategy.name = name;
|
|
760
|
+
}
|
|
761
|
+
if (!strategy.provider) {
|
|
762
|
+
strategy.provider = strategy.name;
|
|
763
|
+
}
|
|
764
|
+
if (hasOwn(strategy, "ssr")) {
|
|
765
|
+
strategy.ssr = strategy.ssr;
|
|
766
|
+
} else {
|
|
767
|
+
strategy.ssr = nuxt.options.ssr;
|
|
768
|
+
}
|
|
769
|
+
const provider = await resolveProvider(strategy.provider, nuxt, strategy);
|
|
770
|
+
delete strategy.provider;
|
|
771
|
+
if (typeof provider === "function") {
|
|
772
|
+
provider(nuxt, strategy);
|
|
773
|
+
}
|
|
774
|
+
if (!strategy.scheme) {
|
|
775
|
+
strategy.scheme = strategy.name;
|
|
776
|
+
}
|
|
777
|
+
try {
|
|
778
|
+
const schemeImport = await resolveScheme(strategy.scheme);
|
|
779
|
+
delete strategy.scheme;
|
|
780
|
+
strategyScheme[strategy.name] = schemeImport;
|
|
781
|
+
strategies.push(strategy);
|
|
782
|
+
} catch (e) {
|
|
783
|
+
console.error(`[Auth] Error resolving strategy ${strategy.name}: ${e}`);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
return {
|
|
787
|
+
strategies,
|
|
788
|
+
strategyScheme
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
async function resolveScheme(scheme) {
|
|
792
|
+
if (typeof scheme !== "string") {
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
if (BuiltinSchemes[scheme]) {
|
|
796
|
+
return {
|
|
797
|
+
name: BuiltinSchemes[scheme],
|
|
798
|
+
as: BuiltinSchemes[scheme],
|
|
799
|
+
from: "#auth/runtime"
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
const path = await resolvePath(scheme);
|
|
803
|
+
if (existsSync(path)) {
|
|
804
|
+
const _path = path.replace(/\\/g, "/");
|
|
805
|
+
return {
|
|
806
|
+
name: "default",
|
|
807
|
+
as: "Scheme$" + hash({ path: _path }),
|
|
808
|
+
from: _path
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
async function resolveProvider(provider, nuxt, strategy) {
|
|
813
|
+
provider = ProviderAliases[provider] || provider;
|
|
814
|
+
if (AUTH_PROVIDERS[provider]) {
|
|
815
|
+
return AUTH_PROVIDERS[provider];
|
|
816
|
+
}
|
|
817
|
+
if (typeof provider === "function") {
|
|
818
|
+
return provider(nuxt, strategy);
|
|
819
|
+
}
|
|
820
|
+
if (typeof provider === "string") {
|
|
821
|
+
return (nuxt2, strategy2) => {
|
|
822
|
+
if (OAuth2Schemes.includes(strategy2.scheme) && strategy2.ssr) {
|
|
823
|
+
assignDefaults(strategy2, OAUTH2DEFAULTS);
|
|
824
|
+
addAuthorize(nuxt2, strategy2, true);
|
|
825
|
+
}
|
|
826
|
+
if (LocalSchemes.includes(strategy2.scheme) && strategy2.ssr) {
|
|
827
|
+
assignDefaults(strategy2, LOCALDEFAULTS);
|
|
828
|
+
if (strategy2.url) {
|
|
829
|
+
assignAbsoluteEndpoints(strategy2);
|
|
830
|
+
}
|
|
831
|
+
addLocalAuthorize(nuxt2, strategy2);
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const moduleDefaults = {
|
|
838
|
+
// -- Enable Global Middleware --
|
|
839
|
+
globalMiddleware: false,
|
|
840
|
+
enableMiddleware: true,
|
|
841
|
+
// -- Error handling --
|
|
842
|
+
resetOnError: false,
|
|
843
|
+
resetOnResponseError: false,
|
|
844
|
+
ignoreExceptions: false,
|
|
845
|
+
// -- Authorization --
|
|
846
|
+
scopeKey: "scope",
|
|
847
|
+
// -- Redirects --
|
|
848
|
+
rewriteRedirects: true,
|
|
849
|
+
fullPathRedirect: false,
|
|
850
|
+
redirectStrategy: "storage",
|
|
851
|
+
watchLoggedIn: true,
|
|
852
|
+
tokenValidationInterval: false,
|
|
853
|
+
redirect: {
|
|
854
|
+
login: "/login",
|
|
855
|
+
logout: "/",
|
|
856
|
+
home: "/",
|
|
857
|
+
callback: "/login"
|
|
858
|
+
},
|
|
859
|
+
stores: {
|
|
860
|
+
state: {
|
|
861
|
+
namespace: "auth"
|
|
862
|
+
},
|
|
863
|
+
pinia: {
|
|
864
|
+
enabled: false,
|
|
865
|
+
namespace: "auth"
|
|
866
|
+
},
|
|
867
|
+
cookie: {
|
|
868
|
+
enabled: true,
|
|
869
|
+
prefix: "auth.",
|
|
870
|
+
options: {
|
|
871
|
+
path: "/",
|
|
872
|
+
sameSite: "lax",
|
|
873
|
+
maxAge: 31536e3
|
|
874
|
+
}
|
|
875
|
+
},
|
|
876
|
+
local: {
|
|
877
|
+
enabled: false,
|
|
878
|
+
prefix: "auth."
|
|
879
|
+
},
|
|
880
|
+
session: {
|
|
881
|
+
enabled: false,
|
|
882
|
+
prefix: "auth."
|
|
883
|
+
}
|
|
884
|
+
},
|
|
885
|
+
// -- Strategies --
|
|
886
|
+
defaultStrategy: void 0,
|
|
887
|
+
strategies: {}
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
const getAuthPlugin = (options) => {
|
|
891
|
+
return `import { Auth, ExpiredAuthSessionError } from '#auth/runtime'
|
|
892
|
+
import { defineNuxtPlugin, useRuntimeConfig } from '#imports'
|
|
893
|
+
import { defu } from 'defu';
|
|
894
|
+
|
|
895
|
+
// Active schemes
|
|
896
|
+
${options.schemeImports.map((i) => `import { ${i.name}${i.name !== i.as ? " as " + i.as : ""} } from '${i.from}'`).join("\n")}
|
|
897
|
+
|
|
898
|
+
// Options
|
|
899
|
+
let options = ${serialize(options.options, { space: 4 })}
|
|
900
|
+
|
|
901
|
+
export default defineNuxtPlugin({
|
|
902
|
+
name: 'nuxt-alt:auth',
|
|
903
|
+
async setup(nuxtApp) {
|
|
904
|
+
// Create a new Auth instance
|
|
905
|
+
const auth = new Auth(nuxtApp, options)
|
|
906
|
+
|
|
907
|
+
// Register strategies
|
|
908
|
+
${options.strategies.map((strategy) => {
|
|
909
|
+
const scheme = options.strategyScheme[strategy.name];
|
|
910
|
+
const schemeOptions = JSON.stringify(strategy);
|
|
911
|
+
return `auth.registerStrategy('${strategy.name}', new ${scheme.as}(auth, defu(useRuntimeConfig()?.public?.auth?.strategies?.['${strategy.name}'], ${schemeOptions})))`;
|
|
912
|
+
}).join(";\n")}
|
|
913
|
+
|
|
914
|
+
nuxtApp.provide('auth', auth)
|
|
915
|
+
|
|
916
|
+
return auth.init()
|
|
917
|
+
.catch(error => {
|
|
918
|
+
if (process.client) {
|
|
919
|
+
// Don't console log expired auth session errors. This error is common, and expected to happen.
|
|
920
|
+
// The error happens whenever the user does an ssr request (reload/initial navigation) with an expired refresh
|
|
921
|
+
// token. We don't want to log this as an error.
|
|
922
|
+
if (error instanceof ExpiredAuthSessionError) {
|
|
923
|
+
return
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
console.error('[ERROR] [AUTH]', error)
|
|
927
|
+
}
|
|
928
|
+
})
|
|
929
|
+
}
|
|
930
|
+
})`;
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
const CONFIG_KEY = "auth";
|
|
934
|
+
const module = defineNuxtModule({
|
|
935
|
+
meta: {
|
|
936
|
+
name,
|
|
937
|
+
version,
|
|
938
|
+
configKey: CONFIG_KEY,
|
|
939
|
+
compatibility: {
|
|
940
|
+
nuxt: "^3.0.0"
|
|
941
|
+
}
|
|
942
|
+
},
|
|
943
|
+
defaults: ({ options }) => ({
|
|
944
|
+
...moduleDefaults,
|
|
945
|
+
stores: {
|
|
946
|
+
cookie: {
|
|
947
|
+
secure: options.dev ? false : true
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}),
|
|
951
|
+
async setup(moduleOptions, nuxt) {
|
|
952
|
+
const resolver = createResolver(import.meta.url);
|
|
953
|
+
const runtime = resolver.resolve("runtime");
|
|
954
|
+
const options = defu(nuxt.options.runtimeConfig[CONFIG_KEY], moduleOptions, moduleDefaults);
|
|
955
|
+
const { strategies, strategyScheme } = await resolveStrategies(nuxt, options);
|
|
956
|
+
delete options.strategies;
|
|
957
|
+
const uniqueImports = /* @__PURE__ */ new Set();
|
|
958
|
+
const schemeImports = Object.values(strategyScheme).filter((i) => {
|
|
959
|
+
if (uniqueImports.has(i.as)) {
|
|
960
|
+
return false;
|
|
961
|
+
}
|
|
962
|
+
uniqueImports.add(i.as);
|
|
963
|
+
return true;
|
|
964
|
+
});
|
|
965
|
+
options.defaultStrategy = options.defaultStrategy || strategies.length ? strategies[0].name : "";
|
|
966
|
+
nuxt.hook("nitro:config", (config) => {
|
|
967
|
+
config.virtual = config.virtual || {};
|
|
968
|
+
config.virtual["#nuxt-auth-options"] = `export const config = ${serialize(options, { space: 4 })}`;
|
|
969
|
+
});
|
|
970
|
+
if (!nuxt.options.modules.includes("@nuxt-alt/http")) {
|
|
971
|
+
installModule("@nuxt-alt/http");
|
|
972
|
+
}
|
|
973
|
+
addPluginTemplate({
|
|
974
|
+
getContents: () => getAuthPlugin({ options, strategies, strategyScheme, schemeImports }),
|
|
975
|
+
filename: "auth.plugin.mjs"
|
|
976
|
+
});
|
|
977
|
+
addImports([
|
|
978
|
+
{ from: resolver.resolve("runtime/composables"), name: "useAuth" }
|
|
979
|
+
]);
|
|
980
|
+
nuxt.options.alias["#auth/runtime"] = runtime;
|
|
981
|
+
const providers = resolver.resolve("runtime/providers");
|
|
982
|
+
nuxt.options.alias["#auth/providers"] = providers;
|
|
983
|
+
const utils = resolver.resolve("utils");
|
|
984
|
+
nuxt.options.alias["#auth/utils"] = utils;
|
|
985
|
+
nuxt.options.build.transpile.push(runtime, providers, utils);
|
|
986
|
+
if (nuxt.options.ssr) {
|
|
987
|
+
addServerHandler({
|
|
988
|
+
route: "/_auth/reset",
|
|
989
|
+
method: "post",
|
|
990
|
+
handler: resolver.resolve(runtime, "token-nitro")
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
if (options.enableMiddleware) {
|
|
994
|
+
addRouteMiddleware({
|
|
995
|
+
name: "auth",
|
|
996
|
+
path: resolver.resolve("runtime/core/middleware"),
|
|
997
|
+
global: options.globalMiddleware
|
|
998
|
+
}, { override: true });
|
|
999
|
+
}
|
|
1000
|
+
if (options.plugins) {
|
|
1001
|
+
options.plugins.forEach((p) => nuxt.options.plugins.push(p));
|
|
1002
|
+
delete options.plugins;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
export { module as default };
|