@auth/solid-start 0.1.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 +15 -0
- package/README.MD +80 -0
- package/client.d.ts +20 -0
- package/client.js +56 -0
- package/index.d.ts +17 -0
- package/index.js +87 -0
- package/package.json +58 -0
- package/src/client.ts +102 -0
- package/src/index.ts +114 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022-2023, Balázs Orbán
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.MD
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Getting started
|
|
2
|
+
|
|
3
|
+
Recommended to use [create-jd-app](https://github.com/OrJDev/create-jd-app)
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @auth/solid-start@latest @auth/core@latest
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Setting It Up
|
|
10
|
+
|
|
11
|
+
[Generate auth secret](https://generate-secret.vercel.app/32), then set it as an environment variable:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
AUTH_SECRET=your_auth_secret
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### On Production
|
|
18
|
+
|
|
19
|
+
Don't forget to trust the host.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
AUTH_TRUST_HOST=true
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Creating the api handler
|
|
26
|
+
|
|
27
|
+
in this example we are using github so make sure to set the following environment variables:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
GITHUB_ID=your_github_oatuh_id
|
|
31
|
+
GITHUB_SECRET=your_github_oatuh_secret
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
// routes/api/auth/[...solidauth].ts
|
|
36
|
+
import { SolidAuth, type SolidAuthConfig } from "@auth/solid-start"
|
|
37
|
+
import GitHub from "@auth/core/providers/github"
|
|
38
|
+
|
|
39
|
+
export const authOpts: SolidAuthConfig = {
|
|
40
|
+
providers: [
|
|
41
|
+
GitHub({
|
|
42
|
+
clientId: process.env.GITHUB_ID,
|
|
43
|
+
clientSecret: process.env.GITHUB_SECRET,
|
|
44
|
+
}),
|
|
45
|
+
],
|
|
46
|
+
debug: false,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const { GET, POST } = SolidAuth(authOpts)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Signing in and out
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { signIn, signOut } from "@auth/solid-start/client"
|
|
56
|
+
const login = () => signIn("github")
|
|
57
|
+
const logout = () => signOut()
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Getting the current session
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { getSession } from "@auth/solid-start"
|
|
64
|
+
import { createServerData$ } from "solid-start/server"
|
|
65
|
+
import { authOpts } from "~/routes/api/auth/[...solidauth]"
|
|
66
|
+
|
|
67
|
+
export const useSession = () => {
|
|
68
|
+
return createServerData$(
|
|
69
|
+
async (_, { request }) => {
|
|
70
|
+
return await getSession(request, authOpts)
|
|
71
|
+
},
|
|
72
|
+
{ key: () => ["auth_user"] }
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// useSession returns a resource:
|
|
77
|
+
const session = useSession()
|
|
78
|
+
const loading = session.loading
|
|
79
|
+
const user = () => session()?.user
|
|
80
|
+
```
|
package/client.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { LiteralUnion, SignInOptions, SignInAuthorizationParams, SignOutParams } from 'next-auth/react';
|
|
2
|
+
import { RedirectableProviderType, BuiltInProviderType } from '@auth/core/providers';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Client-side method to initiate a signin flow
|
|
6
|
+
* or send the user to the signin page listing all possible providers.
|
|
7
|
+
* Automatically adds the CSRF token to the request.
|
|
8
|
+
*
|
|
9
|
+
* [Documentation](https://next-auth.js.org/getting-started/client#signin)
|
|
10
|
+
*/
|
|
11
|
+
declare function signIn<P extends RedirectableProviderType | undefined = undefined>(providerId?: LiteralUnion<P extends RedirectableProviderType ? P | BuiltInProviderType : BuiltInProviderType>, options?: SignInOptions, authorizationParams?: SignInAuthorizationParams): Promise<Response | undefined>;
|
|
12
|
+
/**
|
|
13
|
+
* Signs the user out, by removing the session cookie.
|
|
14
|
+
* Automatically adds the CSRF token to the request.
|
|
15
|
+
*
|
|
16
|
+
* [Documentation](https://next-auth.js.org/getting-started/client#signout)
|
|
17
|
+
*/
|
|
18
|
+
declare function signOut(options?: SignOutParams): Promise<void>;
|
|
19
|
+
|
|
20
|
+
export { signIn, signOut };
|
package/client.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
async function signIn(providerId, options, authorizationParams) {
|
|
2
|
+
const { callbackUrl = window.location.href, redirect = true } = options ?? {};
|
|
3
|
+
const isCredentials = providerId === "credentials";
|
|
4
|
+
const isEmail = providerId === "email";
|
|
5
|
+
const isSupportingReturn = isCredentials || isEmail;
|
|
6
|
+
const signInUrl = `/api/auth/${isCredentials ? "callback" : "signin"}/${providerId}`;
|
|
7
|
+
const _signInUrl = `${signInUrl}?${new URLSearchParams(authorizationParams)}`;
|
|
8
|
+
const csrfTokenResponse = await fetch("/api/auth/csrf");
|
|
9
|
+
const { csrfToken } = await csrfTokenResponse.json();
|
|
10
|
+
const res = await fetch(_signInUrl, {
|
|
11
|
+
method: "post",
|
|
12
|
+
headers: {
|
|
13
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
14
|
+
"X-Auth-Return-Redirect": "1"
|
|
15
|
+
},
|
|
16
|
+
body: new URLSearchParams({
|
|
17
|
+
...options,
|
|
18
|
+
csrfToken,
|
|
19
|
+
callbackUrl
|
|
20
|
+
})
|
|
21
|
+
});
|
|
22
|
+
const data = await res.clone().json();
|
|
23
|
+
const error = new URL(data.url).searchParams.get("error");
|
|
24
|
+
if (redirect || !isSupportingReturn || !error) {
|
|
25
|
+
window.location.href = data.url ?? data.redirect ?? callbackUrl;
|
|
26
|
+
if (data.url.includes("#"))
|
|
27
|
+
window.location.reload();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
return res;
|
|
31
|
+
}
|
|
32
|
+
async function signOut(options) {
|
|
33
|
+
const { callbackUrl = window.location.href } = options ?? {};
|
|
34
|
+
const csrfTokenResponse = await fetch("/api/auth/csrf");
|
|
35
|
+
const { csrfToken } = await csrfTokenResponse.json();
|
|
36
|
+
const res = await fetch(`/api/auth/signout`, {
|
|
37
|
+
method: "post",
|
|
38
|
+
headers: {
|
|
39
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
40
|
+
"X-Auth-Return-Redirect": "1"
|
|
41
|
+
},
|
|
42
|
+
body: new URLSearchParams({
|
|
43
|
+
csrfToken,
|
|
44
|
+
callbackUrl
|
|
45
|
+
})
|
|
46
|
+
});
|
|
47
|
+
const data = await res.json();
|
|
48
|
+
const url = data.url ?? data.redirect ?? callbackUrl;
|
|
49
|
+
window.location.href = url;
|
|
50
|
+
if (url.includes("#"))
|
|
51
|
+
window.location.reload();
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
signIn,
|
|
55
|
+
signOut
|
|
56
|
+
};
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AuthConfig, Session } from '@auth/core/types';
|
|
2
|
+
|
|
3
|
+
interface SolidAuthConfig extends AuthConfig {
|
|
4
|
+
/**
|
|
5
|
+
* Defines the base path for the auth routes.
|
|
6
|
+
* @default '/api/auth'
|
|
7
|
+
*/
|
|
8
|
+
prefix?: string;
|
|
9
|
+
}
|
|
10
|
+
declare function SolidAuth(config: SolidAuthConfig): {
|
|
11
|
+
GET(event: any): Promise<Response | undefined>;
|
|
12
|
+
POST(event: any): Promise<Response | undefined>;
|
|
13
|
+
};
|
|
14
|
+
type GetSessionResult = Promise<Session | null>;
|
|
15
|
+
declare function getSession(req: Request, options: AuthConfig): GetSessionResult;
|
|
16
|
+
|
|
17
|
+
export { GetSessionResult, SolidAuth, SolidAuthConfig, getSession };
|
package/index.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Auth } from "@auth/core";
|
|
2
|
+
import { parseString, splitCookiesString } from "set-cookie-parser";
|
|
3
|
+
import { serialize } from "cookie";
|
|
4
|
+
const actions = [
|
|
5
|
+
"providers",
|
|
6
|
+
"session",
|
|
7
|
+
"csrf",
|
|
8
|
+
"signin",
|
|
9
|
+
"signout",
|
|
10
|
+
"callback",
|
|
11
|
+
"verify-request",
|
|
12
|
+
"error"
|
|
13
|
+
];
|
|
14
|
+
const getSetCookieCallback = (cook) => {
|
|
15
|
+
if (!cook)
|
|
16
|
+
return;
|
|
17
|
+
const splitCookie = splitCookiesString(cook);
|
|
18
|
+
for (const cookName of [
|
|
19
|
+
"__Secure-next-auth.session-token",
|
|
20
|
+
"next-auth.session-token",
|
|
21
|
+
"next-auth.pkce.code_verifier",
|
|
22
|
+
"__Secure-next-auth.pkce.code_verifier"
|
|
23
|
+
]) {
|
|
24
|
+
const temp = splitCookie.find((e) => e.startsWith(`${cookName}=`));
|
|
25
|
+
if (temp) {
|
|
26
|
+
return parseString(temp);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return parseString(splitCookie?.[0] ?? "");
|
|
30
|
+
};
|
|
31
|
+
function SolidAuthHandler(prefix, authOptions) {
|
|
32
|
+
return async (event) => {
|
|
33
|
+
const { request } = event;
|
|
34
|
+
const url = new URL(request.url);
|
|
35
|
+
const action = url.pathname.slice(prefix.length + 1).split("/")[0];
|
|
36
|
+
if (!actions.includes(action) || !url.pathname.startsWith(prefix + "/")) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const res = await Auth(request, authOptions);
|
|
40
|
+
if (["callback", "signin", "signout"].includes(action)) {
|
|
41
|
+
const parsedCookie = getSetCookieCallback(
|
|
42
|
+
res.clone().headers.get("Set-Cookie")
|
|
43
|
+
);
|
|
44
|
+
if (parsedCookie) {
|
|
45
|
+
res.headers.set(
|
|
46
|
+
"Set-Cookie",
|
|
47
|
+
serialize(parsedCookie.name, parsedCookie.value, parsedCookie)
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return res;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function SolidAuth(config) {
|
|
55
|
+
const { prefix = "/api/auth", ...authOptions } = config;
|
|
56
|
+
authOptions.secret ??= process.env.AUTH_SECRET;
|
|
57
|
+
authOptions.trustHost ??= !!(process.env.AUTH_TRUST_HOST ?? process.env.VERCEL ?? process.env.NODE_ENV !== "production");
|
|
58
|
+
const handler = SolidAuthHandler(prefix, authOptions);
|
|
59
|
+
return {
|
|
60
|
+
async GET(event) {
|
|
61
|
+
return await handler(event);
|
|
62
|
+
},
|
|
63
|
+
async POST(event) {
|
|
64
|
+
return await handler(event);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async function getSession(req, options) {
|
|
69
|
+
options.secret ??= process.env.AUTH_SECRET;
|
|
70
|
+
options.trustHost ??= true;
|
|
71
|
+
const url = new URL("/api/auth/session", req.url);
|
|
72
|
+
const response = await Auth(
|
|
73
|
+
new Request(url, { headers: req.headers }),
|
|
74
|
+
options
|
|
75
|
+
);
|
|
76
|
+
const { status = 200 } = response;
|
|
77
|
+
const data = await response.json();
|
|
78
|
+
if (!data || !Object.keys(data).length)
|
|
79
|
+
return null;
|
|
80
|
+
if (status === 200)
|
|
81
|
+
return data;
|
|
82
|
+
throw new Error(data.message);
|
|
83
|
+
}
|
|
84
|
+
export {
|
|
85
|
+
SolidAuth,
|
|
86
|
+
getSession
|
|
87
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@auth/solid-start",
|
|
3
|
+
"description": "Authentication for SolidStart.",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"client.*",
|
|
8
|
+
"index.*",
|
|
9
|
+
"src"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./index.d.ts",
|
|
14
|
+
"import": "./index.js"
|
|
15
|
+
},
|
|
16
|
+
"./client": {
|
|
17
|
+
"types": "./client.d.ts",
|
|
18
|
+
"import": "./client.js"
|
|
19
|
+
},
|
|
20
|
+
"./package.json": "./package.json"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@solidjs/meta": "^0.28.0",
|
|
27
|
+
"@types/cookie": "0.5.1",
|
|
28
|
+
"@types/node": "^18.7.14",
|
|
29
|
+
"@types/set-cookie-parser": "^2.4.2",
|
|
30
|
+
"solid-js": "^1.5.7",
|
|
31
|
+
"solid-start": "^0.2.1",
|
|
32
|
+
"tsup": "^6.5.0",
|
|
33
|
+
"typescript": "^4.8.2",
|
|
34
|
+
"@auth/core": "0.2.3",
|
|
35
|
+
"next-auth": "4.18.6"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"@auth/core": "~0.2.2 || ^0.2.2",
|
|
39
|
+
"solid-js": "^1.5.7",
|
|
40
|
+
"solid-start": "^0.2.1"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"set-cookie-parser": "^2.5.1"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"SolidJS",
|
|
47
|
+
"SolidStart",
|
|
48
|
+
"Auth"
|
|
49
|
+
],
|
|
50
|
+
"author": "OrJDev <orjdeveloper@gmail.com>",
|
|
51
|
+
"repository": "https://github.com/nextauthjs/next-auth",
|
|
52
|
+
"license": "ISC",
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsup --config ./tsup.config.js && node scripts/postbuild",
|
|
55
|
+
"patch": "npm version patch --no-git-tag-version",
|
|
56
|
+
"clean": "rm -rf client.* index.*"
|
|
57
|
+
}
|
|
58
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
LiteralUnion,
|
|
3
|
+
SignInOptions,
|
|
4
|
+
SignInAuthorizationParams,
|
|
5
|
+
SignOutParams,
|
|
6
|
+
} from "next-auth/react"
|
|
7
|
+
import type {
|
|
8
|
+
BuiltInProviderType,
|
|
9
|
+
RedirectableProviderType,
|
|
10
|
+
} from "@auth/core/providers"
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Client-side method to initiate a signin flow
|
|
14
|
+
* or send the user to the signin page listing all possible providers.
|
|
15
|
+
* Automatically adds the CSRF token to the request.
|
|
16
|
+
*
|
|
17
|
+
* [Documentation](https://next-auth.js.org/getting-started/client#signin)
|
|
18
|
+
*/
|
|
19
|
+
export async function signIn<
|
|
20
|
+
P extends RedirectableProviderType | undefined = undefined
|
|
21
|
+
>(
|
|
22
|
+
providerId?: LiteralUnion<
|
|
23
|
+
P extends RedirectableProviderType
|
|
24
|
+
? P | BuiltInProviderType
|
|
25
|
+
: BuiltInProviderType
|
|
26
|
+
>,
|
|
27
|
+
options?: SignInOptions,
|
|
28
|
+
authorizationParams?: SignInAuthorizationParams
|
|
29
|
+
) {
|
|
30
|
+
const { callbackUrl = window.location.href, redirect = true } = options ?? {}
|
|
31
|
+
|
|
32
|
+
// TODO: Support custom providers
|
|
33
|
+
const isCredentials = providerId === "credentials"
|
|
34
|
+
const isEmail = providerId === "email"
|
|
35
|
+
const isSupportingReturn = isCredentials || isEmail
|
|
36
|
+
|
|
37
|
+
// TODO: Handle custom base path
|
|
38
|
+
const signInUrl = `/api/auth/${
|
|
39
|
+
isCredentials ? "callback" : "signin"
|
|
40
|
+
}/${providerId}`
|
|
41
|
+
|
|
42
|
+
const _signInUrl = `${signInUrl}?${new URLSearchParams(authorizationParams)}`
|
|
43
|
+
|
|
44
|
+
// TODO: Handle custom base path
|
|
45
|
+
const csrfTokenResponse = await fetch("/api/auth/csrf")
|
|
46
|
+
const { csrfToken } = await csrfTokenResponse.json()
|
|
47
|
+
|
|
48
|
+
const res = await fetch(_signInUrl, {
|
|
49
|
+
method: "post",
|
|
50
|
+
headers: {
|
|
51
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
52
|
+
"X-Auth-Return-Redirect": "1",
|
|
53
|
+
},
|
|
54
|
+
// @ts-expect-error -- ignore
|
|
55
|
+
body: new URLSearchParams({
|
|
56
|
+
...options,
|
|
57
|
+
csrfToken,
|
|
58
|
+
callbackUrl,
|
|
59
|
+
}),
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const data = await res.clone().json()
|
|
63
|
+
const error = new URL(data.url).searchParams.get("error")
|
|
64
|
+
if (redirect || !isSupportingReturn || !error) {
|
|
65
|
+
// TODO: Do not redirect for Credentials and Email providers by default in next major
|
|
66
|
+
window.location.href = data.url ?? data.redirect ?? callbackUrl
|
|
67
|
+
// If url contains a hash, the browser does not reload the page. We reload manually
|
|
68
|
+
if (data.url.includes("#")) window.location.reload()
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
return res
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Signs the user out, by removing the session cookie.
|
|
76
|
+
* Automatically adds the CSRF token to the request.
|
|
77
|
+
*
|
|
78
|
+
* [Documentation](https://next-auth.js.org/getting-started/client#signout)
|
|
79
|
+
*/
|
|
80
|
+
export async function signOut(options?: SignOutParams) {
|
|
81
|
+
const { callbackUrl = window.location.href } = options ?? {}
|
|
82
|
+
// TODO: Custom base path
|
|
83
|
+
const csrfTokenResponse = await fetch("/api/auth/csrf")
|
|
84
|
+
const { csrfToken } = await csrfTokenResponse.json()
|
|
85
|
+
const res = await fetch(`/api/auth/signout`, {
|
|
86
|
+
method: "post",
|
|
87
|
+
headers: {
|
|
88
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
89
|
+
"X-Auth-Return-Redirect": "1",
|
|
90
|
+
},
|
|
91
|
+
body: new URLSearchParams({
|
|
92
|
+
csrfToken,
|
|
93
|
+
callbackUrl,
|
|
94
|
+
}),
|
|
95
|
+
})
|
|
96
|
+
const data = await res.json()
|
|
97
|
+
|
|
98
|
+
const url = data.url ?? data.redirect ?? callbackUrl
|
|
99
|
+
window.location.href = url
|
|
100
|
+
// If url contains a hash, the browser does not reload the page. We reload manually
|
|
101
|
+
if (url.includes("#")) window.location.reload()
|
|
102
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Auth } from "@auth/core"
|
|
2
|
+
import { Cookie, parseString, splitCookiesString } from "set-cookie-parser"
|
|
3
|
+
import { serialize } from "cookie"
|
|
4
|
+
import type { AuthAction, AuthConfig, Session } from "@auth/core/types"
|
|
5
|
+
|
|
6
|
+
export interface SolidAuthConfig extends AuthConfig {
|
|
7
|
+
/**
|
|
8
|
+
* Defines the base path for the auth routes.
|
|
9
|
+
* @default '/api/auth'
|
|
10
|
+
*/
|
|
11
|
+
prefix?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const actions: AuthAction[] = [
|
|
15
|
+
"providers",
|
|
16
|
+
"session",
|
|
17
|
+
"csrf",
|
|
18
|
+
"signin",
|
|
19
|
+
"signout",
|
|
20
|
+
"callback",
|
|
21
|
+
"verify-request",
|
|
22
|
+
"error",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
// currently multiple cookies are not supported, so we keep the next-auth.pkce.code_verifier cookie for now:
|
|
26
|
+
// because it gets updated anyways
|
|
27
|
+
// src: https://github.com/solidjs/solid-start/issues/293
|
|
28
|
+
const getSetCookieCallback = (cook?: string | null): Cookie | undefined => {
|
|
29
|
+
if (!cook) return
|
|
30
|
+
const splitCookie = splitCookiesString(cook)
|
|
31
|
+
for (const cookName of [
|
|
32
|
+
"__Secure-next-auth.session-token",
|
|
33
|
+
"next-auth.session-token",
|
|
34
|
+
"next-auth.pkce.code_verifier",
|
|
35
|
+
"__Secure-next-auth.pkce.code_verifier",
|
|
36
|
+
]) {
|
|
37
|
+
const temp = splitCookie.find((e) => e.startsWith(`${cookName}=`))
|
|
38
|
+
if (temp) {
|
|
39
|
+
return parseString(temp)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return parseString(splitCookie?.[0] ?? "") // just return the first cookie if no session token is found
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function SolidAuthHandler(prefix: string, authOptions: SolidAuthConfig) {
|
|
46
|
+
return async (event: any) => {
|
|
47
|
+
const { request } = event
|
|
48
|
+
const url = new URL(request.url)
|
|
49
|
+
const action = url.pathname
|
|
50
|
+
.slice(prefix.length + 1)
|
|
51
|
+
.split("/")[0] as AuthAction
|
|
52
|
+
|
|
53
|
+
if (!actions.includes(action) || !url.pathname.startsWith(prefix + "/")) {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const res = await Auth(request, authOptions)
|
|
58
|
+
if (["callback", "signin", "signout"].includes(action)) {
|
|
59
|
+
const parsedCookie = getSetCookieCallback(
|
|
60
|
+
res.clone().headers.get("Set-Cookie")
|
|
61
|
+
)
|
|
62
|
+
if (parsedCookie) {
|
|
63
|
+
res.headers.set(
|
|
64
|
+
"Set-Cookie",
|
|
65
|
+
serialize(parsedCookie.name, parsedCookie.value, parsedCookie as any)
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return res
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function SolidAuth(config: SolidAuthConfig) {
|
|
74
|
+
const { prefix = "/api/auth", ...authOptions } = config
|
|
75
|
+
authOptions.secret ??= process.env.AUTH_SECRET
|
|
76
|
+
authOptions.trustHost ??= !!(
|
|
77
|
+
process.env.AUTH_TRUST_HOST ??
|
|
78
|
+
process.env.VERCEL ??
|
|
79
|
+
process.env.NODE_ENV !== "production"
|
|
80
|
+
)
|
|
81
|
+
const handler = SolidAuthHandler(prefix, authOptions)
|
|
82
|
+
return {
|
|
83
|
+
async GET(event: any) {
|
|
84
|
+
return await handler(event)
|
|
85
|
+
},
|
|
86
|
+
async POST(event: any) {
|
|
87
|
+
return await handler(event)
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export type GetSessionResult = Promise<Session | null>
|
|
93
|
+
|
|
94
|
+
export async function getSession(
|
|
95
|
+
req: Request,
|
|
96
|
+
options: AuthConfig
|
|
97
|
+
): GetSessionResult {
|
|
98
|
+
options.secret ??= process.env.AUTH_SECRET
|
|
99
|
+
options.trustHost ??= true
|
|
100
|
+
|
|
101
|
+
const url = new URL("/api/auth/session", req.url)
|
|
102
|
+
const response = await Auth(
|
|
103
|
+
new Request(url, { headers: req.headers }),
|
|
104
|
+
options
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
const { status = 200 } = response
|
|
108
|
+
|
|
109
|
+
const data = await response.json()
|
|
110
|
+
|
|
111
|
+
if (!data || !Object.keys(data).length) return null
|
|
112
|
+
if (status === 200) return data
|
|
113
|
+
throw new Error(data.message)
|
|
114
|
+
}
|