nuxt-auther 1.0.1 → 1.0.3
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
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
export const isUnset = (o) => typeof o === "undefined" || o === null;
|
|
2
|
+
export const isSet = (o) => !isUnset(o);
|
|
3
|
+
export function parseQuery(queryString) {
|
|
4
|
+
const query = {};
|
|
5
|
+
const pairs = queryString.split("&");
|
|
6
|
+
for (let i = 0; i < pairs.length; i++) {
|
|
7
|
+
const pair = pairs[i].split("=");
|
|
8
|
+
query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || "");
|
|
9
|
+
}
|
|
10
|
+
return query;
|
|
11
|
+
}
|
|
12
|
+
export function isRelativeURL(u) {
|
|
13
|
+
return u && u.length && new RegExp(["^\\/([a-zA-Z0-9@\\-%_~.:]", "[/a-zA-Z0-9@\\-%_~.:]*)?", "([?][^#]*)?(#[^#]*)?$"].join("")).test(u);
|
|
14
|
+
}
|
|
15
|
+
export function routeMeta(route, key, value) {
|
|
16
|
+
return route.meta[key] === value;
|
|
17
|
+
}
|
|
18
|
+
export function getMatchedComponents(route, matches = []) {
|
|
19
|
+
return [
|
|
20
|
+
...route.matched.map(function(m, index) {
|
|
21
|
+
return Object.keys(m.components).map(function(key) {
|
|
22
|
+
matches.push(index);
|
|
23
|
+
return m.components[key];
|
|
24
|
+
});
|
|
25
|
+
})
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
export function normalizePath(path = "", ctx) {
|
|
29
|
+
let result = path.split("?")[0];
|
|
30
|
+
if (ctx.$config.app.baseURL) {
|
|
31
|
+
result = result.replace(ctx.$config.app.baseURL, "/");
|
|
32
|
+
}
|
|
33
|
+
if (result.charAt(result.length - 1) === "/") {
|
|
34
|
+
result = result.slice(0, -1);
|
|
35
|
+
}
|
|
36
|
+
result = result.replace(/\/+/g, "/");
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
export function encodeValue(val) {
|
|
40
|
+
if (typeof val === "string") {
|
|
41
|
+
return val;
|
|
42
|
+
}
|
|
43
|
+
return JSON.stringify(val);
|
|
44
|
+
}
|
|
45
|
+
export function decodeValue(val) {
|
|
46
|
+
if (typeof val === "string") {
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(val);
|
|
49
|
+
} catch (_) {
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return val;
|
|
53
|
+
}
|
|
54
|
+
export function getProp(holder, propName) {
|
|
55
|
+
if (isJSON(holder)) {
|
|
56
|
+
holder = JSON.parse(holder);
|
|
57
|
+
}
|
|
58
|
+
if (!propName || !holder || typeof holder !== "object") {
|
|
59
|
+
return holder;
|
|
60
|
+
}
|
|
61
|
+
if (propName in holder) {
|
|
62
|
+
return holder[propName];
|
|
63
|
+
}
|
|
64
|
+
const propParts = Array.isArray(propName) ? propName : propName.split(".");
|
|
65
|
+
let result = holder;
|
|
66
|
+
for (let part of propParts) {
|
|
67
|
+
if (result[part] === void 0) {
|
|
68
|
+
return void 0;
|
|
69
|
+
}
|
|
70
|
+
result = result[part];
|
|
71
|
+
}
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
function isJSON(str) {
|
|
75
|
+
try {
|
|
76
|
+
JSON.parse(str);
|
|
77
|
+
} catch (e) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
export function addTokenPrefix(token, tokenType) {
|
|
83
|
+
if (!token || !tokenType || typeof token !== "string" || token.startsWith(tokenType)) {
|
|
84
|
+
return token;
|
|
85
|
+
}
|
|
86
|
+
return tokenType + " " + token;
|
|
87
|
+
}
|
|
88
|
+
export function removeTokenPrefix(token, tokenType) {
|
|
89
|
+
if (!token || !tokenType || typeof token !== "string") {
|
|
90
|
+
return token;
|
|
91
|
+
}
|
|
92
|
+
return token.replace(tokenType + " ", "");
|
|
93
|
+
}
|
|
94
|
+
export function cleanObj(obj) {
|
|
95
|
+
for (const key in obj) {
|
|
96
|
+
if (obj[key] === void 0) {
|
|
97
|
+
delete obj[key];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return obj;
|
|
101
|
+
}
|
|
102
|
+
export function randomString(length) {
|
|
103
|
+
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
104
|
+
let result = "";
|
|
105
|
+
const charactersLength = characters.length;
|
|
106
|
+
for (let i = 0; i < length; i++) {
|
|
107
|
+
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
export function setH3Cookie(event, serializedCookie) {
|
|
112
|
+
let cookies = event.node.res.getHeader("Set-Cookie") || [];
|
|
113
|
+
if (!Array.isArray(cookies)) cookies = [cookies];
|
|
114
|
+
cookies.unshift(serializedCookie);
|
|
115
|
+
if (!event.node.res.headersSent) {
|
|
116
|
+
event.node.res.setHeader("Set-Cookie", cookies.filter(
|
|
117
|
+
(value, index, items) => items.findIndex(
|
|
118
|
+
(val) => val.startsWith(value.slice(0, value.indexOf("=")))
|
|
119
|
+
) === index
|
|
120
|
+
));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export const hasOwn = (object, key) => Object.hasOwn ? Object.hasOwn(object, key) : Object.prototype.hasOwnProperty.call(object, key);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Oauth2SchemeOptions, RefreshSchemeOptions } from '../runtime';
|
|
2
|
+
import type { StrategyOptions, TokenableSchemeOptions } from '../types';
|
|
3
|
+
import type { Nuxt } from '@nuxt/schema';
|
|
4
|
+
export declare function assignDefaults<SOptions extends StrategyOptions>(strategy: SOptions, defaults: SOptions): void;
|
|
5
|
+
export declare function addAuthorize<SOptions extends StrategyOptions<Oauth2SchemeOptions>>(nuxt: Nuxt, strategy: SOptions, useForms?: boolean): void;
|
|
6
|
+
export declare function addLocalAuthorize<SOptions extends StrategyOptions<RefreshSchemeOptions>>(nuxt: Nuxt, strategy: SOptions): void;
|
|
7
|
+
export declare function initializePasswordGrantFlow<SOptions extends StrategyOptions<RefreshSchemeOptions>>(nuxt: Nuxt, strategy: SOptions): void;
|
|
8
|
+
export declare function assignAbsoluteEndpoints<SOptions extends StrategyOptions<(TokenableSchemeOptions | RefreshSchemeOptions) & {
|
|
9
|
+
url: string;
|
|
10
|
+
}>>(strategy: SOptions): void;
|
|
11
|
+
export declare function authorizeGrant(opt: any): string;
|
|
12
|
+
export declare function localAuthorizeGrant(opt: any): string;
|
|
13
|
+
export declare function passwordGrant(opt: any): string;
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import { addServerHandler, addTemplate } from "@nuxt/kit";
|
|
2
|
+
import { serialize } from "@refactorjs/serialize";
|
|
3
|
+
import { join } from "pathe";
|
|
4
|
+
import { defu } from "defu";
|
|
5
|
+
export function assignDefaults(strategy, defaults) {
|
|
6
|
+
Object.assign(strategy, defu(strategy, defaults));
|
|
7
|
+
}
|
|
8
|
+
export function addAuthorize(nuxt, strategy, useForms = false) {
|
|
9
|
+
const clientSecret = strategy.clientSecret;
|
|
10
|
+
const clientId = strategy.clientId;
|
|
11
|
+
const tokenEndpoint = strategy.endpoints.token;
|
|
12
|
+
const audience = strategy.audience;
|
|
13
|
+
delete strategy.clientSecret;
|
|
14
|
+
const endpoint = `/_auth/oauth/${strategy.name}/authorize`;
|
|
15
|
+
strategy.endpoints.token = endpoint;
|
|
16
|
+
strategy.responseType = "code";
|
|
17
|
+
addTemplate({
|
|
18
|
+
filename: `authorize-${strategy.name}.ts`,
|
|
19
|
+
write: true,
|
|
20
|
+
getContents: () => authorizeGrant({
|
|
21
|
+
strategy,
|
|
22
|
+
useForms,
|
|
23
|
+
clientSecret,
|
|
24
|
+
clientId,
|
|
25
|
+
tokenEndpoint,
|
|
26
|
+
audience
|
|
27
|
+
})
|
|
28
|
+
});
|
|
29
|
+
addServerHandler({
|
|
30
|
+
route: endpoint,
|
|
31
|
+
method: "post",
|
|
32
|
+
handler: join(nuxt.options.buildDir, `authorize-${strategy.name}.ts`)
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export function addLocalAuthorize(nuxt, strategy) {
|
|
36
|
+
const tokenEndpoint = strategy.endpoints?.login?.url;
|
|
37
|
+
const refreshEndpoint = strategy.endpoints?.refresh?.url;
|
|
38
|
+
const endpoint = `/_auth/local/${strategy.name}/authorize`;
|
|
39
|
+
strategy.endpoints.login.url = endpoint;
|
|
40
|
+
strategy.endpoints.refresh.url = endpoint;
|
|
41
|
+
addTemplate({
|
|
42
|
+
filename: `local-${strategy.name}.ts`,
|
|
43
|
+
write: true,
|
|
44
|
+
getContents: () => localAuthorizeGrant({
|
|
45
|
+
strategy,
|
|
46
|
+
tokenEndpoint,
|
|
47
|
+
refreshEndpoint
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
addServerHandler({
|
|
51
|
+
route: endpoint,
|
|
52
|
+
method: "post",
|
|
53
|
+
handler: join(nuxt.options.buildDir, `local-${strategy.name}.ts`)
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
export function initializePasswordGrantFlow(nuxt, strategy) {
|
|
57
|
+
const clientSecret = strategy.clientSecret;
|
|
58
|
+
const clientId = strategy.clientId;
|
|
59
|
+
const tokenEndpoint = strategy.endpoints.token;
|
|
60
|
+
delete strategy.clientSecret;
|
|
61
|
+
const endpoint = `/_auth/${strategy.name}/token`;
|
|
62
|
+
strategy.endpoints.login.url = endpoint;
|
|
63
|
+
strategy.endpoints.refresh.url = endpoint;
|
|
64
|
+
addTemplate({
|
|
65
|
+
filename: `password-${strategy.name}.ts`,
|
|
66
|
+
write: true,
|
|
67
|
+
getContents: () => passwordGrant({
|
|
68
|
+
strategy,
|
|
69
|
+
clientSecret,
|
|
70
|
+
clientId,
|
|
71
|
+
tokenEndpoint
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
addServerHandler({
|
|
75
|
+
route: endpoint,
|
|
76
|
+
method: "post",
|
|
77
|
+
handler: join(nuxt.options.buildDir, `password-${strategy.name}.ts`)
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
export function assignAbsoluteEndpoints(strategy) {
|
|
81
|
+
const { url, endpoints } = strategy;
|
|
82
|
+
if (endpoints) {
|
|
83
|
+
for (const key of Object.keys(endpoints)) {
|
|
84
|
+
const endpoint = endpoints[key];
|
|
85
|
+
if (endpoint) {
|
|
86
|
+
if (typeof endpoint === "object") {
|
|
87
|
+
if (!endpoint.url || endpoint.url.startsWith(url)) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
endpoints[key].url = url + endpoint.url;
|
|
91
|
+
} else {
|
|
92
|
+
if (endpoint.startsWith(url)) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
endpoints[key] = url + endpoint;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export function authorizeGrant(opt) {
|
|
102
|
+
return `import { defineEventHandler, readBody, createError, getCookie } from 'h3'
|
|
103
|
+
// @ts-expect-error: virtual file
|
|
104
|
+
import { config } from '#nuxt-auth-options'
|
|
105
|
+
import { serialize } from 'cookie-es'
|
|
106
|
+
|
|
107
|
+
const options = ${serialize(opt, { space: 4 })}
|
|
108
|
+
|
|
109
|
+
function addTokenPrefix(token: string | boolean, tokenType: string | false): string | boolean {
|
|
110
|
+
if (!token || !tokenType || typeof token !== 'string' || token.startsWith(tokenType)) {
|
|
111
|
+
return token;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return tokenType + ' ' + token;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export default defineEventHandler(async (event) => {
|
|
118
|
+
const {
|
|
119
|
+
code,
|
|
120
|
+
code_verifier: codeVerifier,
|
|
121
|
+
redirect_uri: redirectUri = options.strategy.redirectUri,
|
|
122
|
+
response_type: responseType = options.strategy.responseType,
|
|
123
|
+
grant_type: grantType = options.strategy.grantType,
|
|
124
|
+
refresh_token: refreshToken
|
|
125
|
+
} = await readBody(event)
|
|
126
|
+
|
|
127
|
+
const refreshCookieName = config.stores.cookie.prefix + options.strategy?.refreshToken?.prefix + options.strategy.name
|
|
128
|
+
const tokenCookieName = config.stores.cookie.prefix + options.strategy?.token?.prefix + options.strategy.name
|
|
129
|
+
const idTokenCookieName = config.stores.cookie.prefix + options.strategy?.idToken?.prefix + options.strategy.name
|
|
130
|
+
const serverRefreshToken = getCookie(event, refreshCookieName)
|
|
131
|
+
|
|
132
|
+
// Grant type is authorization code, but code is not available
|
|
133
|
+
if (grantType === 'authorization_code' && !code) {
|
|
134
|
+
return createError({
|
|
135
|
+
statusCode: 500,
|
|
136
|
+
message: 'Missing authorization code'
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Grant type is refresh token, but refresh token is not available
|
|
141
|
+
if ((grantType === 'refresh_token' && !options.strategy.refreshToken.httpOnly && !refreshToken) || (grantType === 'refresh_token' && options.strategy.refreshToken.httpOnly && !serverRefreshToken)) {
|
|
142
|
+
return createError({
|
|
143
|
+
statusCode: 500,
|
|
144
|
+
message: 'Missing refresh token'
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let body = {
|
|
149
|
+
client_id: options.clientId,
|
|
150
|
+
client_secret: options.clientSecret,
|
|
151
|
+
refresh_token: options.strategy.refreshToken.httpOnly ? serverRefreshToken : refreshToken,
|
|
152
|
+
grant_type: grantType,
|
|
153
|
+
response_type: responseType,
|
|
154
|
+
redirect_uri: redirectUri,
|
|
155
|
+
audience: options.audience,
|
|
156
|
+
code_verifier: codeVerifier,
|
|
157
|
+
code
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (grantType !== 'refresh_token') {
|
|
161
|
+
delete body.refresh_token
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const headers = {
|
|
165
|
+
Accept: 'application/json',
|
|
166
|
+
'Content-Type': 'application/json'
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (options.strategy.clientSecretTransport === 'authorization_header') {
|
|
170
|
+
// @ts-ignore
|
|
171
|
+
headers['Authorization'] = 'Basic ' + Buffer.from(options.clientId + ':' + options.clientSecret).toString('base64')
|
|
172
|
+
// client_secret is transported in auth header
|
|
173
|
+
delete body.client_secret
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const response = await $http.post(options.tokenEndpoint, {
|
|
177
|
+
body,
|
|
178
|
+
headers
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
let cookies = event.node.res.getHeader('Set-Cookie') as string[] || [];
|
|
182
|
+
|
|
183
|
+
const refreshCookieValue = response._data?.[options.strategy?.refreshToken?.property]
|
|
184
|
+
if (config.stores.cookie.enabled && refreshCookieValue && options.strategy.refreshToken.httpOnly) {
|
|
185
|
+
const refreshCookie = serialize(refreshCookieName, refreshCookieValue, { ...config.stores.cookie.options, httpOnly: true })
|
|
186
|
+
cookies.push(refreshCookie);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const tokenCookieValue = response._data?.[options.strategy?.token?.property]
|
|
190
|
+
if (config.stores.cookie.enabled && tokenCookieValue && options.strategy.token.httpOnly) {
|
|
191
|
+
const token = addTokenPrefix(tokenCookieValue, options.strategy.token.type) as string
|
|
192
|
+
const tokenCookie = serialize(tokenCookieName, token, { ...config.stores.cookie.options, httpOnly: true })
|
|
193
|
+
cookies.push(tokenCookie);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const idTokenCookieValue = response._data?.[options.strategy?.idToken?.property]
|
|
197
|
+
if (config.stores.cookie.enabled && idTokenCookieValue && options.strategy.idToken.httpOnly) {
|
|
198
|
+
const idTokenCookie = serialize(idTokenCookieName, token, { ...config.stores.cookie.options, httpOnly: true })
|
|
199
|
+
cookies.push(idTokenCookie);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (cookies.length) {
|
|
203
|
+
event.node.res.setHeader('Set-Cookie', cookies);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
event.node.res.end(JSON.stringify(response._data))
|
|
207
|
+
})
|
|
208
|
+
`;
|
|
209
|
+
}
|
|
210
|
+
export function localAuthorizeGrant(opt) {
|
|
211
|
+
return `import { defineEventHandler, readBody, createError, getCookie, getRequestHeader } from 'h3'
|
|
212
|
+
// @ts-expect-error: virtual file
|
|
213
|
+
import { config } from '#nuxt-auth-options'
|
|
214
|
+
import { serialize } from 'cookie-es'
|
|
215
|
+
|
|
216
|
+
const options = ${serialize(opt, { space: 4 })}
|
|
217
|
+
|
|
218
|
+
function addTokenPrefix(token: string | boolean, tokenType: string | false): string | boolean {
|
|
219
|
+
if (!token || !tokenType || typeof token !== 'string' || token.startsWith(tokenType)) {
|
|
220
|
+
return token;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return tokenType + ' ' + token;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export default defineEventHandler(async (event) => {
|
|
227
|
+
const requestBody = await readBody(event)
|
|
228
|
+
|
|
229
|
+
const refreshCookieName = config.stores.cookie.prefix + options.strategy?.refreshToken?.prefix + options.strategy.name
|
|
230
|
+
const refreshTokenDataName = options.strategy.refreshToken.data
|
|
231
|
+
const tokenCookieName = config.stores.cookie.prefix + options.strategy?.token?.prefix + options.strategy.name
|
|
232
|
+
const serverRefreshToken = getCookie(event, refreshCookieName)
|
|
233
|
+
const authHeader = getRequestHeader(event, 'authorization')
|
|
234
|
+
|
|
235
|
+
// Grant type is refresh token, but refresh token is not available
|
|
236
|
+
if ((requestBody.grant_type === 'refresh_token' && !options.strategy.refreshToken.httpOnly && !requestBody[refreshTokenDataName]) || (requestBody.grant_type === 'refresh_token' && options.strategy.refreshToken.httpOnly && !serverRefreshToken)) {
|
|
237
|
+
return createError({
|
|
238
|
+
statusCode: 500,
|
|
239
|
+
message: 'Missing refresh token'
|
|
240
|
+
})
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
let body = {
|
|
244
|
+
...requestBody,
|
|
245
|
+
[refreshTokenDataName]: options.strategy.refreshToken.httpOnly ? serverRefreshToken : requestBody[refreshTokenDataName],
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (requestBody.grant_type !== 'refresh_token') {
|
|
249
|
+
delete body[refreshTokenDataName]
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
let headers = {
|
|
253
|
+
'Content-Type': 'application/json'
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
let response
|
|
257
|
+
|
|
258
|
+
if (body[refreshTokenDataName]) {
|
|
259
|
+
if (options.strategy?.refreshToken?.tokenRequired && authHeader) {
|
|
260
|
+
headers = {
|
|
261
|
+
...headers,
|
|
262
|
+
// @ts-ignore
|
|
263
|
+
Authorization: authHeader,
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
response = await $http.post(options.refreshEndpoint, {
|
|
268
|
+
body,
|
|
269
|
+
headers: {
|
|
270
|
+
...headers,
|
|
271
|
+
// @ts-ignore: headers might not be set
|
|
272
|
+
...options.strategy?.endpoints?.refresh?.headers
|
|
273
|
+
}
|
|
274
|
+
})
|
|
275
|
+
} else {
|
|
276
|
+
response = await $http.post(options.tokenEndpoint, {
|
|
277
|
+
body,
|
|
278
|
+
headers: {
|
|
279
|
+
...headers,
|
|
280
|
+
// @ts-ignore: headers might not be set
|
|
281
|
+
...options.strategy?.endpoints?.login?.headers
|
|
282
|
+
}
|
|
283
|
+
})
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
let cookies = event.node.res.getHeader('Set-Cookie') as string[] || [];
|
|
287
|
+
|
|
288
|
+
const refreshCookieValue = response._data?.[options.strategy?.refreshToken?.property]
|
|
289
|
+
if (config.stores.cookie.enabled && refreshCookieValue && options.strategy.refreshToken.httpOnly) {
|
|
290
|
+
const refreshCookie = serialize(refreshCookieName, refreshCookieValue, { ...config.stores.cookie.options, httpOnly: true })
|
|
291
|
+
cookies.push(refreshCookie);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const tokenCookieValue = response._data?.[options.strategy?.token?.property]
|
|
295
|
+
if (config.stores.cookie.enabled && tokenCookieValue && options.strategy.token.httpOnly) {
|
|
296
|
+
const token = addTokenPrefix(tokenCookieValue, options.strategy.token.type) as string
|
|
297
|
+
const tokenCookie = serialize(tokenCookieName, token, { ...config.stores.cookie.options, httpOnly: true })
|
|
298
|
+
cookies.push(tokenCookie);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (cookies.length) {
|
|
302
|
+
event.node.res.setHeader('Set-Cookie', cookies);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
event.node.res.end(JSON.stringify(response._data))
|
|
306
|
+
})
|
|
307
|
+
`;
|
|
308
|
+
}
|
|
309
|
+
export function passwordGrant(opt) {
|
|
310
|
+
return `import requrl from 'requrl';
|
|
311
|
+
import { defineEventHandler, readBody, createError } from 'h3';
|
|
312
|
+
|
|
313
|
+
const options = ${serialize(opt, { space: 4 })}
|
|
314
|
+
|
|
315
|
+
export default defineEventHandler(async (event) => {
|
|
316
|
+
const body = await readBody(event)
|
|
317
|
+
|
|
318
|
+
// If \`grant_type\` is not defined, set default value
|
|
319
|
+
if (!body.grant_type) {
|
|
320
|
+
body.grant_type = options.strategy.grantType
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// If \`client_id\` is not defined, set default value
|
|
324
|
+
if (!body.client_id) {
|
|
325
|
+
body.grant_type = options.clientId
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Grant type is password, but username or password is not available
|
|
329
|
+
if (body.grant_type === 'password' && (!body.username || !body.password)) {
|
|
330
|
+
return createError({
|
|
331
|
+
statusCode: 400,
|
|
332
|
+
message: 'Invalid username or password'
|
|
333
|
+
})
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Grant type is refresh token, but refresh token is not available
|
|
337
|
+
if (body.grant_type === 'refresh_token' && !body.refresh_token) {
|
|
338
|
+
event.respondWith({ status: 400, body: JSON.stringify({ message: 'Refresh token not provided' }) });
|
|
339
|
+
return createError({
|
|
340
|
+
statusCode: 400,
|
|
341
|
+
message: 'Refresh token not provided'
|
|
342
|
+
})
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const response = await $http.post(options.tokenEndpoint, {
|
|
346
|
+
baseURL: requrl(event.node.req),
|
|
347
|
+
body: {
|
|
348
|
+
client_id: options.clientId,
|
|
349
|
+
client_secret: options.clientSecret,
|
|
350
|
+
...body
|
|
351
|
+
},
|
|
352
|
+
headers: {
|
|
353
|
+
Accept: 'application/json'
|
|
354
|
+
}
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
event.node.res.end(JSON.stringify(response._data))
|
|
358
|
+
})
|
|
359
|
+
`;
|
|
360
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-auther",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Authentication module for Nuxt.JS",
|
|
5
5
|
"homepage": "https://github.com/zerosdev/nuxt-auther",
|
|
6
6
|
"author": "zerosdev",
|
|
@@ -31,7 +31,9 @@
|
|
|
31
31
|
],
|
|
32
32
|
"scripts": {
|
|
33
33
|
"dev": "nuxi dev playground",
|
|
34
|
-
"dev:build": "nuxi build playground"
|
|
34
|
+
"dev:build": "nuxi build playground",
|
|
35
|
+
"dev:prepare": "set JITI_ESM_RESOLVE=1 && jiti ./commands/cli.ts build --stub && set JITI_ESM_RESOLVE=1 && jiti ./commands/cli.ts prepare",
|
|
36
|
+
"prepack": "set JITI_ESM_RESOLVE=1 && jiti ./commands/cli.ts build"
|
|
35
37
|
},
|
|
36
38
|
"dependencies": {
|
|
37
39
|
"@nuxt-alt/http": "latest",
|
|
@@ -52,7 +54,7 @@
|
|
|
52
54
|
"@types/node": "^20",
|
|
53
55
|
"jiti": "^1.21.6",
|
|
54
56
|
"nuxt": "^3.9.3",
|
|
55
|
-
"typescript": "5.3.3",
|
|
57
|
+
"typescript": "^5.3.3",
|
|
56
58
|
"unbuild": "^2.0.0"
|
|
57
59
|
},
|
|
58
60
|
"repository": {
|