mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
324 Commits
@auth/soli
...
feat/nextj
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54876744fe | ||
|
|
28cbb3aac5 | ||
|
|
ac0ca51278 | ||
|
|
5400645221 | ||
|
|
d739e8e04e | ||
|
|
c2eb9b3ad4 | ||
|
|
6111662df7 | ||
|
|
5da6549c48 | ||
|
|
1ca87809d6 | ||
|
|
7f6967fc3c | ||
|
|
2313ef63e0 | ||
|
|
523fcbab71 | ||
|
|
4f54840014 | ||
|
|
d938333750 | ||
|
|
83d8b447db | ||
|
|
d837dfaea1 | ||
|
|
a99f4bd8c6 | ||
|
|
a96b8597b1 | ||
|
|
ddffa57d00 | ||
|
|
807d5d7920 | ||
|
|
29ce4cb4d4 | ||
|
|
da40242e48 | ||
|
|
3f211e7ad0 | ||
|
|
5f369b0981 | ||
|
|
4a056c774f | ||
|
|
0f0dd9228a | ||
|
|
b087fdb817 | ||
|
|
038b9bccad | ||
|
|
dfb20849c5 | ||
|
|
4a7a7ab757 | ||
|
|
f94b604397 | ||
|
|
535f9276f6 | ||
|
|
cd2872de89 | ||
|
|
443bfd6c32 | ||
|
|
7c44d916ed | ||
|
|
b489fef2e2 | ||
|
|
2de2dc9bb3 | ||
|
|
6f96004d75 | ||
|
|
f834bc2a99 | ||
|
|
551dcbd2d5 | ||
|
|
316b344930 | ||
|
|
97ff6406cb | ||
|
|
98add24526 | ||
|
|
1b9559fbb1 | ||
|
|
27864eea2f | ||
|
|
e5f18e3266 | ||
|
|
47eec2c498 | ||
|
|
77bba4ada7 | ||
|
|
f081fcd31d | ||
|
|
5f079930cc | ||
|
|
4cc4b45e52 | ||
|
|
c0cfb13c88 | ||
|
|
0ddd47cc0a | ||
|
|
0100888d9b | ||
|
|
9eeea02fe2 | ||
|
|
0a57fea430 | ||
|
|
51750e1a06 | ||
|
|
537112a306 | ||
|
|
039a14d992 | ||
|
|
da821d2789 | ||
|
|
be5c42e350 | ||
|
|
b68f461f8b | ||
|
|
95c5ba0b5d | ||
|
|
25388de027 | ||
|
|
ad77e1c2b7 | ||
|
|
cd654c3001 | ||
|
|
6f9ca4143d | ||
|
|
6663003c7c | ||
|
|
68559941a5 | ||
|
|
cec1fd753e | ||
|
|
c97c40c9cb | ||
|
|
e97b27414a | ||
|
|
9018939ee7 | ||
|
|
c2fc41b44d | ||
|
|
01d7eb4feb | ||
|
|
2388c20cc6 | ||
|
|
9a1bef9e72 | ||
|
|
35a72d2273 | ||
|
|
5f1b75a7a2 | ||
|
|
fa58065951 | ||
|
|
defc2233be | ||
|
|
e0450c9d52 | ||
|
|
04021c6d47 | ||
|
|
210d28b6b0 | ||
|
|
fcd9bfc6f8 | ||
|
|
0a027cf35d | ||
|
|
47ac2e94ce | ||
|
|
30e3672708 | ||
|
|
635a9b0c50 | ||
|
|
510b9764f5 | ||
|
|
7329725702 | ||
|
|
23ea9428e0 | ||
|
|
319f7af866 | ||
|
|
b31f2af66c | ||
|
|
71bb6f2590 | ||
|
|
58be169b10 | ||
|
|
c87fdd9060 | ||
|
|
28263f52bd | ||
|
|
6c07331cc5 | ||
|
|
c8ef94b2be | ||
|
|
75a59fbd92 | ||
|
|
27869b70b8 | ||
|
|
7af7ca4d1c | ||
|
|
3dd47b0735 | ||
|
|
4dc1d421f8 | ||
|
|
30948fbada | ||
|
|
99ca67f1cf | ||
|
|
a087df8494 | ||
|
|
1aa4994de6 | ||
|
|
88023f69b9 | ||
|
|
b02057a72d | ||
|
|
400da8c766 | ||
|
|
b48104801b | ||
|
|
ccbbc800d2 | ||
|
|
d7888263ca | ||
|
|
47d3151410 | ||
|
|
7d264860ab | ||
|
|
6184b936f5 | ||
|
|
1954258a0a | ||
|
|
c580f0db22 | ||
|
|
d1cf701ed9 | ||
|
|
69398e2d3a | ||
|
|
856b5c50fc | ||
|
|
2830b7de5b | ||
|
|
40a0faa586 | ||
|
|
a6b4d958ac | ||
|
|
cc13df9d51 | ||
|
|
06b8d4772c | ||
|
|
d644d1fcbf | ||
|
|
380f2de961 | ||
|
|
dc5f3e1873 | ||
|
|
93f3fcd1b7 | ||
|
|
1d9b9ba47c | ||
|
|
8f6108f230 | ||
|
|
15943d6696 | ||
|
|
81589bf738 | ||
|
|
09402bf2fc | ||
|
|
e39a968a7b | ||
|
|
b03378be7f | ||
|
|
af415e9438 | ||
|
|
90eeeeab2f | ||
|
|
f0b475fc72 | ||
|
|
f4f8c4a0b3 | ||
|
|
6f2cb460c9 | ||
|
|
46f285f6f0 | ||
|
|
6bdb8af78d | ||
|
|
04e0637fd8 | ||
|
|
b5712448a1 | ||
|
|
605d15c3cc | ||
|
|
d1479125cb | ||
|
|
2e09bc0d19 | ||
|
|
843fc6ff8f | ||
|
|
6695ff8503 | ||
|
|
80c1f375b8 | ||
|
|
5a13288d47 | ||
|
|
26201e6271 | ||
|
|
d0d7b90ba1 | ||
|
|
874624dfbe | ||
|
|
4b5cd08800 | ||
|
|
1c104afef9 | ||
|
|
ff5b8ba8e2 | ||
|
|
42d5899efd | ||
|
|
b278975c3f | ||
|
|
997e595b5b | ||
|
|
527c25b128 | ||
|
|
0e2bbda537 | ||
|
|
7f3b35593f | ||
|
|
bce6b00c43 | ||
|
|
1bbd5d51d1 | ||
|
|
b24b02fe71 | ||
|
|
2c5c4d18c4 | ||
|
|
e3f9b398f0 | ||
|
|
ab13930020 | ||
|
|
f6bb16b264 | ||
|
|
a220245d03 | ||
|
|
7462e797de | ||
|
|
36286b1fae | ||
|
|
2e8e90a9be | ||
|
|
d06a552bf6 | ||
|
|
5cb8dd5f37 | ||
|
|
7c1a3b547e | ||
|
|
2534ae8801 | ||
|
|
14a120277b | ||
|
|
c49f484743 | ||
|
|
676b39d5b1 | ||
|
|
e27dbcab2f | ||
|
|
63805c7d75 | ||
|
|
5d1c35e8aa | ||
|
|
a77f557cbf | ||
|
|
657492d921 | ||
|
|
d1d63bddba | ||
|
|
99ac4899b5 | ||
|
|
2130765a57 | ||
|
|
4079274aaf | ||
|
|
3d7985fd6d | ||
|
|
331e0ce51e | ||
|
|
8af666a4cc | ||
|
|
fed0a67917 | ||
|
|
0332d86942 | ||
|
|
8b38d32430 | ||
|
|
1e5f840a26 | ||
|
|
5981712681 | ||
|
|
dd2b85c6a5 | ||
|
|
3c0475acae | ||
|
|
416881c4c9 | ||
|
|
b91167091c | ||
|
|
497dacff41 | ||
|
|
2a1e1d1cd2 | ||
|
|
00f65b3476 | ||
|
|
470e55f8db | ||
|
|
d722962206 | ||
|
|
cee1bddbd5 | ||
|
|
e0ae913e5c | ||
|
|
1db27fcd07 | ||
|
|
95407df289 | ||
|
|
22adc2eb3c | ||
|
|
725f976b39 | ||
|
|
28ae5d4639 | ||
|
|
0f4d43e9ad | ||
|
|
28583b8ab0 | ||
|
|
1e7538a955 | ||
|
|
4258857e52 | ||
|
|
e9d8805609 | ||
|
|
fb43c5da05 | ||
|
|
326eadf0ed | ||
|
|
a5e0db4bb3 | ||
|
|
334e23343a | ||
|
|
be046a6cb2 | ||
|
|
bdee262abe | ||
|
|
3f89e668ec | ||
|
|
533320eb94 | ||
|
|
dfe6509472 | ||
|
|
1bde7cc8df | ||
|
|
cef05d5e2d | ||
|
|
c0dea283ba | ||
|
|
0204766e0f | ||
|
|
a336ba762c | ||
|
|
681d53c2f8 | ||
|
|
06e891c0ea | ||
|
|
b9a84350b5 | ||
|
|
44c38247da | ||
|
|
9b9af4d5e5 | ||
|
|
fd2179bdca | ||
|
|
7bb037bb9d | ||
|
|
52f70e9f4f | ||
|
|
505f69b519 | ||
|
|
b21709db40 | ||
|
|
aff7b37ef9 | ||
|
|
daa85be1ad | ||
|
|
c31718ca10 | ||
|
|
fbcfedf0e8 | ||
|
|
bd032335eb | ||
|
|
128e0f3a10 | ||
|
|
557fb9d741 | ||
|
|
b4d6ed5f5f | ||
|
|
035836da98 | ||
|
|
294039a497 | ||
|
|
b2450ef625 | ||
|
|
a81bb3e51e | ||
|
|
bb506f7eb9 | ||
|
|
87d9cc4244 | ||
|
|
d2e3b76031 | ||
|
|
c36834b3b0 | ||
|
|
8f7145801a | ||
|
|
fdce27b8ca | ||
|
|
4056dafa7a | ||
|
|
f0b61bd5fd | ||
|
|
866e42b343 | ||
|
|
6d4cde4b02 | ||
|
|
2377596bb6 | ||
|
|
3c7c25cefa | ||
|
|
c441f681af | ||
|
|
c05951f0f9 | ||
|
|
d142252499 | ||
|
|
700daec919 | ||
|
|
d8481f3825 | ||
|
|
3539a35601 | ||
|
|
3be7bb7a79 | ||
|
|
031cdd13b2 | ||
|
|
212b321f7e | ||
|
|
1ccb88b3f0 | ||
|
|
16d680b110 | ||
|
|
6e027811ef | ||
|
|
e5df406429 | ||
|
|
e4ddb533ff | ||
|
|
4e16b21a60 | ||
|
|
dd9f1b7421 | ||
|
|
4ebec5d385 | ||
|
|
c1f3cbda3c | ||
|
|
ba3ed049d1 | ||
|
|
9238294192 | ||
|
|
83c6bfe237 | ||
|
|
07109616c8 | ||
|
|
95c8f7930e | ||
|
|
8005f0cdb0 | ||
|
|
6e0ae59ed3 | ||
|
|
1b19aa39b8 | ||
|
|
69cda58707 | ||
|
|
b20a5f554a | ||
|
|
f8d77c4daf | ||
|
|
a3d23450a8 | ||
|
|
9abee0b2ee | ||
|
|
5cf580d10b | ||
|
|
00d495d9e3 | ||
|
|
5884574765 | ||
|
|
ae5360b028 | ||
|
|
7c963515b5 | ||
|
|
8cf4cc2ea9 | ||
|
|
9388a56efa | ||
|
|
3a75fb955a | ||
|
|
01bb91612a | ||
|
|
3b25935c83 | ||
|
|
394920dfd4 | ||
|
|
85dc5bede8 | ||
|
|
8f854c61d0 | ||
|
|
e8fbe58997 | ||
|
|
d2288ee4cc | ||
|
|
5a6f76bf2c | ||
|
|
15bed6260c | ||
|
|
1423733d61 | ||
|
|
77d8f47f51 | ||
|
|
3120d28299 | ||
|
|
e6a320bb0f | ||
|
|
7d4d436efe |
@@ -1,70 +0,0 @@
|
|||||||
.eslintrc.js
|
|
||||||
.cache-loader
|
|
||||||
.DS_Store
|
|
||||||
.pnpm-debug.log
|
|
||||||
.turbo
|
|
||||||
.vscode/generated*
|
|
||||||
/_work
|
|
||||||
/actions-runner
|
|
||||||
node_modules
|
|
||||||
patches
|
|
||||||
pnpm-lock.yaml
|
|
||||||
.github/actions/issue-validator/index.mjs
|
|
||||||
*.cjs
|
|
||||||
*.js
|
|
||||||
*.d.ts
|
|
||||||
*.d.ts.map
|
|
||||||
|
|
||||||
.svelte-kit
|
|
||||||
.next
|
|
||||||
.nuxt
|
|
||||||
|
|
||||||
# --------------- Docs ---------------
|
|
||||||
|
|
||||||
.docusaurus
|
|
||||||
build
|
|
||||||
docs/docs/reference/03-core
|
|
||||||
docs/docs/reference/04-sveltekit
|
|
||||||
static
|
|
||||||
|
|
||||||
# --------------- Packages ---------------
|
|
||||||
|
|
||||||
coverage
|
|
||||||
dist
|
|
||||||
|
|
||||||
# @auth/core
|
|
||||||
packages/core/src/providers/oauth-types.ts
|
|
||||||
packages/core/src/lib/pages/styles.ts
|
|
||||||
|
|
||||||
# @auth/sveltekit
|
|
||||||
packages/frameworks-sveltekit/package
|
|
||||||
packages/frameworks-sveltekit/vite.config.{js,ts}.timestamp-*
|
|
||||||
|
|
||||||
# next-auth
|
|
||||||
packages/next-auth/src/providers/oauth-types.ts
|
|
||||||
packages/next-auth/css/index.css
|
|
||||||
|
|
||||||
|
|
||||||
# Adapters
|
|
||||||
.branches
|
|
||||||
db.sqlite
|
|
||||||
dev.db
|
|
||||||
dynamodblocal-bin
|
|
||||||
firebase-debug.log
|
|
||||||
firestore-debug.log
|
|
||||||
migrations
|
|
||||||
test.schema.gql
|
|
||||||
|
|
||||||
# --------------- Apps ---------------
|
|
||||||
|
|
||||||
|
|
||||||
# Examples should have their own Prettier config since they are templates too
|
|
||||||
apps/example-sveltekit
|
|
||||||
|
|
||||||
# Development app
|
|
||||||
apps
|
|
||||||
|
|
||||||
|
|
||||||
# --------------- Tests ---------------
|
|
||||||
# TODO: these should be linted
|
|
||||||
packages/**/*test*
|
|
||||||
75
.eslintrc.js
75
.eslintrc.js
@@ -1,75 +0,0 @@
|
|||||||
// @ts-check
|
|
||||||
|
|
||||||
/** @type {import("eslint").ESLint.ConfigData} */
|
|
||||||
module.exports = {
|
|
||||||
env: { browser: true, es2022: true, node: true },
|
|
||||||
extends: ["eslint:recommended", "prettier"],
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ["*.ts", "*.tsx"],
|
|
||||||
parser: "@typescript-eslint/parser",
|
|
||||||
parserOptions: {
|
|
||||||
project: ["./packages/**/tsconfig.json", "./apps/**/tsconfig.json"],
|
|
||||||
},
|
|
||||||
settings: { react: { version: "18" } },
|
|
||||||
extends: [
|
|
||||||
"plugin:react/recommended",
|
|
||||||
"plugin:react/jsx-runtime",
|
|
||||||
"standard-with-typescript",
|
|
||||||
"prettier",
|
|
||||||
],
|
|
||||||
rules: {
|
|
||||||
"@typescript-eslint/explicit-function-return-type": "off",
|
|
||||||
"@typescript-eslint/method-signature-style": "off",
|
|
||||||
"@typescript-eslint/naming-convention": "off",
|
|
||||||
"@typescript-eslint/no-non-null-assertion": "off",
|
|
||||||
"@typescript-eslint/restrict-template-expressions": "off",
|
|
||||||
"@typescript-eslint/strict-boolean-expressions": "off",
|
|
||||||
"react/prop-types": "off",
|
|
||||||
"react/no-unescaped-entities": "off",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ["*.test.ts", "*.test.js"],
|
|
||||||
extends: ["plugin:jest/recommended"],
|
|
||||||
env: { jest: true },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ["docs/**"],
|
|
||||||
plugins: ["@docusaurus"],
|
|
||||||
extends: ["plugin:@docusaurus/recommended"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// TODO: Expand to all packages
|
|
||||||
files: ["packages/{core,sveltekit}/*.ts"],
|
|
||||||
plugins: ["jsdoc"],
|
|
||||||
extends: ["plugin:jsdoc/recommended"],
|
|
||||||
rules: {
|
|
||||||
"jsdoc/require-param": "off",
|
|
||||||
"jsdoc/require-returns": "off",
|
|
||||||
"jsdoc/require-jsdoc": [
|
|
||||||
"warn",
|
|
||||||
{ publicOnly: true, enableFixer: false },
|
|
||||||
],
|
|
||||||
"jsdoc/no-multi-asterisks": ["warn", { allowWhitespace: true }],
|
|
||||||
"jsdoc/tag-lines": "off",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ["packages/frameworks-sveltekit"],
|
|
||||||
plugins: ["svelte3"],
|
|
||||||
overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }],
|
|
||||||
settings: {
|
|
||||||
"svelte3/typescript": () => require("typescript"),
|
|
||||||
},
|
|
||||||
parserOptions: { sourceType: "module", ecmaVersion: 2020 },
|
|
||||||
env: { browser: true, es2017: true, node: true },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
parserOptions: {
|
|
||||||
sourceType: "module",
|
|
||||||
ecmaVersion: "latest",
|
|
||||||
ecmaFeatures: { jsx: true },
|
|
||||||
},
|
|
||||||
root: true,
|
|
||||||
}
|
|
||||||
2
.github/ISSUE_TEMPLATE/1_bug_framework.yml
vendored
2
.github/ISSUE_TEMPLATE/1_bug_framework.yml
vendored
@@ -30,7 +30,7 @@ body:
|
|||||||
Run this command in your project's root folder and paste the result:
|
Run this command in your project's root folder and paste the result:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npx envinfo --system --binaries --browsers --npmPackages "next,react,next-auth"
|
npx envinfo --system --binaries --browsers --npmPackages "next,react,next-auth,@auth/*"
|
||||||
```
|
```
|
||||||
Alternatively, you can manually gather the version information from your package.json for these packages: "next", "react" and "next-auth". Please also mention your OS and Node.js version, as well as the browser you are using.
|
Alternatively, you can manually gather the version information from your package.json for these packages: "next", "react" and "next-auth". Please also mention your OS and Node.js version, as well as the browser you are using.
|
||||||
validations:
|
validations:
|
||||||
|
|||||||
5
.github/ISSUE_TEMPLATE/2_bug_provider.yml
vendored
5
.github/ISSUE_TEMPLATE/2_bug_provider.yml
vendored
@@ -25,12 +25,14 @@ body:
|
|||||||
- "Custom provider"
|
- "Custom provider"
|
||||||
- "42 School"
|
- "42 School"
|
||||||
- "Apple"
|
- "Apple"
|
||||||
|
- "Asgardeo"
|
||||||
- "Atlassian"
|
- "Atlassian"
|
||||||
- "Auth0"
|
- "Auth0"
|
||||||
- "Authentik"
|
- "Authentik"
|
||||||
- "Azure Active Directory"
|
- "Azure Active Directory"
|
||||||
- "Azure Active Directory B2C"
|
- "Azure Active Directory B2C"
|
||||||
- "Battlenet"
|
- "Battlenet"
|
||||||
|
- "Beyond Identity"
|
||||||
- "Box"
|
- "Box"
|
||||||
- "Bungie"
|
- "Bungie"
|
||||||
- "Cognito"
|
- "Cognito"
|
||||||
@@ -57,6 +59,7 @@ body:
|
|||||||
- "Medium"
|
- "Medium"
|
||||||
- "Naver"
|
- "Naver"
|
||||||
- "Netlify"
|
- "Netlify"
|
||||||
|
- "Notion"
|
||||||
- "Okta"
|
- "Okta"
|
||||||
- "OneLogin"
|
- "OneLogin"
|
||||||
- "Osso"
|
- "Osso"
|
||||||
@@ -87,7 +90,7 @@ body:
|
|||||||
Run this command in your project's root folder and paste the result:
|
Run this command in your project's root folder and paste the result:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npx envinfo --system --binaries --browsers --npmPackages "next,react,next-auth"
|
npx envinfo --system --binaries --browsers --npmPackages "next,react,next-auth,@auth/*"
|
||||||
```
|
```
|
||||||
Alternatively, you can manually gather the version information from your package.json for these packages: "next", "react" and "next-auth". Please also mention your OS and Node.js version, as well as the browser you are using.
|
Alternatively, you can manually gather the version information from your package.json for these packages: "next", "react" and "next-auth". Please also mention your OS and Node.js version, as well as the browser you are using.
|
||||||
validations:
|
validations:
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
2
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
@@ -44,7 +44,7 @@ body:
|
|||||||
Run this command in your project's root folder and paste the result:
|
Run this command in your project's root folder and paste the result:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npx envinfo --system --binaries --browsers --npmPackages "next,react,next-auth" && npx envinfo --npmPackages "@next-auth/*"
|
npx envinfo --system --binaries --browsers --npmPackages "next,react,next-auth,@auth/*" && npx envinfo --npmPackages "@next-auth/*"
|
||||||
```
|
```
|
||||||
Alternatively, if the above command did not work, we need the version of the following packages from your package.json: "next", "react", "next-auth" and your adapter. Please also mention your OS and Node.js version, as well as the browser you are using.
|
Alternatively, if the above command did not work, we need the version of the following packages from your package.json: "next", "react", "next-auth" and your adapter. Please also mention your OS and Node.js version, as well as the browser you are using.
|
||||||
validations:
|
validations:
|
||||||
|
|||||||
2
.github/actions/issue-validator/index.mjs
vendored
2
.github/actions/issue-validator/index.mjs
vendored
File diff suppressed because one or more lines are too long
4
.github/actions/issue-validator/repro.md
vendored
4
.github/actions/issue-validator/repro.md
vendored
@@ -14,9 +14,9 @@ Ensure the link is pointing to a codebase that is accessible (e.g. not a private
|
|||||||
|
|
||||||
### **What happens if I don't provide a sufficient minimal reproduction?**
|
### **What happens if I don't provide a sufficient minimal reproduction?**
|
||||||
|
|
||||||
Issues with the `incomplete` label that receives no meaningful activity (e.g. new comments with a reproduction link) are automatically closed and locked after 30 days.
|
Issues with the `incomplete` label that receives no meaningful activity (e.g. new comments with a reproduction link) are closed after 7 days.
|
||||||
|
|
||||||
If your issue has _not_ been resolved in that time and it has been closed/locked, please open a new issue with the required reproduction.
|
If your issue has _not_ been resolved in that time and it has been closed/locked, please open a new issue with the required reproduction. (It's less likely that we check back on already closed issues.)
|
||||||
|
|
||||||
### **I did not open this issue, but it is relevant to me, what can I do to help?**
|
### **I did not open this issue, but it is relevant to me, what can I do to help?**
|
||||||
|
|
||||||
|
|||||||
12
.github/actions/issue-validator/src/index.mjs
vendored
12
.github/actions/issue-validator/src/index.mjs
vendored
@@ -41,13 +41,7 @@ async function run() {
|
|||||||
label: { name: newLabel },
|
label: { name: newLabel },
|
||||||
} = payload
|
} = payload
|
||||||
|
|
||||||
if (
|
if (pull_request || !issue?.body || !process.env.GITHUB_TOKEN) return
|
||||||
pull_request ||
|
|
||||||
!issue?.body ||
|
|
||||||
!process.env.GITHUB_TOKEN ||
|
|
||||||
!process.env.GITHUB_ACTION_PATH
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
const labels = issue.labels.map((l) => l.name)
|
const labels = issue.labels.map((l) => l.name)
|
||||||
// const isBugReport =
|
// const isBugReport =
|
||||||
@@ -78,7 +72,9 @@ async function run() {
|
|||||||
client.issues.createComment({
|
client.issues.createComment({
|
||||||
...issueCommon,
|
...issueCommon,
|
||||||
body: readFileSync(
|
body: readFileSync(
|
||||||
join(process.env.GITHUB_ACTION_PATH, "repro.md"),
|
join(
|
||||||
|
"/home/runner/work/next-auth/next-auth/.github/actions/issue-validator/repro.md"
|
||||||
|
),
|
||||||
"utf8"
|
"utf8"
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
|
|||||||
24
.github/sync.yml
vendored
24
.github/sync.yml
vendored
@@ -1,5 +1,3 @@
|
|||||||
# Note that nextauthjs/next-auth-example syncs from the v4 branch
|
|
||||||
|
|
||||||
nextauthjs/sveltekit-auth-example:
|
nextauthjs/sveltekit-auth-example:
|
||||||
- source: apps/examples/sveltekit
|
- source: apps/examples/sveltekit
|
||||||
dest: .
|
dest: .
|
||||||
@@ -7,15 +5,12 @@ nextauthjs/sveltekit-auth-example:
|
|||||||
- .github/FUNDING.yml
|
- .github/FUNDING.yml
|
||||||
- LICENSE
|
- LICENSE
|
||||||
|
|
||||||
# FIXME: Should re-enable, but currently fails:
|
nextauthjs/solid-start-auth-example:
|
||||||
# https://github.com/nextauthjs/next-auth/actions/runs/3811709391/jobs/6484533340
|
- source: "apps/examples/solid-start"
|
||||||
# (issue seems to be the name of the target repo)
|
dest: .
|
||||||
# nextauthjs/solid-start-auth-example:
|
deleteOrphaned: true
|
||||||
# - source: "apps/examples/solid-start"
|
- .github/FUNDING.yml
|
||||||
# dest: .
|
- LICENSE
|
||||||
# deleteOrphaned: true
|
|
||||||
# - .github/FUNDING.yml
|
|
||||||
# - LICENSE
|
|
||||||
|
|
||||||
nextauthjs/next-auth-gatsby-example:
|
nextauthjs/next-auth-gatsby-example:
|
||||||
- source: apps/playgrounds/gatsby
|
- source: apps/playgrounds/gatsby
|
||||||
@@ -23,3 +18,10 @@ nextauthjs/next-auth-gatsby-example:
|
|||||||
deleteOrphaned: true
|
deleteOrphaned: true
|
||||||
- .github/FUNDING.yml
|
- .github/FUNDING.yml
|
||||||
- LICENSE
|
- LICENSE
|
||||||
|
|
||||||
|
nextauthjs/next-auth-example:
|
||||||
|
- source: apps/examples/nextjs
|
||||||
|
dest: .
|
||||||
|
deleteOrphaned: true
|
||||||
|
- .github/FUNDING.yml
|
||||||
|
- LICENSE
|
||||||
|
|||||||
2
.github/workflows/issue-validator.yml
vendored
2
.github/workflows/issue-validator.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
- name: "Run issue validator"
|
- name: Run issue validator
|
||||||
run: node /home/runner/work/next-auth/next-auth/.github/actions/issue-validator/index.mjs
|
run: node /home/runner/work/next-auth/next-auth/.github/actions/issue-validator/index.mjs
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
27
.github/workflows/release.yml
vendored
27
.github/workflows/release.yml
vendored
@@ -3,10 +3,10 @@ name: Release
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- "main"
|
- main
|
||||||
- "beta"
|
- beta
|
||||||
- "next"
|
- next
|
||||||
- "3.x"
|
- 3.x
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -24,7 +24,6 @@ jobs:
|
|||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
cache: "pnpm"
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install
|
run: pnpm install
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
@@ -35,6 +34,22 @@ jobs:
|
|||||||
UPSTASH_REDIS_KEY: ${{ secrets.UPSTASH_REDIS_KEY }}
|
UPSTASH_REDIS_KEY: ${{ secrets.UPSTASH_REDIS_KEY }}
|
||||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||||
|
# - name: Run E2E tests
|
||||||
|
# if: github.repository == 'nextauthjs/next-auth'
|
||||||
|
# run: pnpm e2e
|
||||||
|
# timeout-minutes: 15
|
||||||
|
# env:
|
||||||
|
# AUTH0_USERNAME: ${{ secrets.AUTH0_USERNAME }}
|
||||||
|
# AUTH0_PASSWORD: ${{ secrets.AUTH0_PASSWORD }}
|
||||||
|
# TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||||
|
# TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||||
|
# - name: Upload E2E artifacts
|
||||||
|
# if: github.repository == 'nextauthjs/next-auth'
|
||||||
|
# uses: actions/upload-artifact@v3
|
||||||
|
# with:
|
||||||
|
# name: playwright-report
|
||||||
|
# path: apps/dev/nextjs/playwright-report/
|
||||||
|
# retention-days: 30
|
||||||
# - name: Coverage
|
# - name: Coverage
|
||||||
# uses: codecov/codecov-action@v1
|
# uses: codecov/codecov-action@v1
|
||||||
# with:
|
# with:
|
||||||
@@ -58,7 +73,6 @@ jobs:
|
|||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
cache: "pnpm"
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install
|
run: pnpm install
|
||||||
- name: Publish to npm and GitHub
|
- name: Publish to npm and GitHub
|
||||||
@@ -83,7 +97,6 @@ jobs:
|
|||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
cache: "pnpm"
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install
|
run: pnpm install
|
||||||
- name: Determine version
|
- name: Determine version
|
||||||
|
|||||||
6
.github/workflows/sync-examples.yml
vendored
6
.github/workflows/sync-examples.yml
vendored
@@ -11,9 +11,9 @@ jobs:
|
|||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- name: Run GitHub File Sync
|
- name: Run GitHub File Sync
|
||||||
# Can update to v1 when https://github.com/BetaHuhn/repo-file-sync-action/issues/168 is resolved
|
uses: balazsorban44/repo-file-sync-action@master
|
||||||
uses: BetaHuhn/repo-file-sync-action@v1.16.5
|
|
||||||
with:
|
with:
|
||||||
GH_PAT: ${{ secrets.GH_PAT_CLASSIC }}
|
GH_PAT: ${{ secrets.GH_PAT }}
|
||||||
|
IS_FINE_GRAINED: true
|
||||||
SKIP_PR: true
|
SKIP_PR: true
|
||||||
ORIGINAL_MESSAGE: true
|
ORIGINAL_MESSAGE: true
|
||||||
|
|||||||
39
.gitignore
vendored
39
.gitignore
vendored
@@ -1,6 +1,5 @@
|
|||||||
# Misc
|
# Misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.npmrc
|
|
||||||
.eslintcache
|
.eslintcache
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
@@ -12,8 +11,9 @@ npm-debug.log*
|
|||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
firebase-debug.log
|
firebase-debug.log
|
||||||
|
ui-debug.log
|
||||||
.pnpm-debug.log
|
.pnpm-debug.log
|
||||||
|
.husky
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
node_modules
|
node_modules
|
||||||
@@ -26,26 +26,16 @@ dist
|
|||||||
# Generated files
|
# Generated files
|
||||||
.docusaurus
|
.docusaurus
|
||||||
.cache-loader
|
.cache-loader
|
||||||
packages/next-auth/providers
|
|
||||||
packages/next-auth/src/providers/oauth-types.ts
|
packages/*/*.js
|
||||||
packages/next-auth/client
|
packages/*/*.d.ts
|
||||||
packages/next-auth/css
|
packages/*/*.d.ts.map
|
||||||
packages/next-auth/utils
|
|
||||||
packages/next-auth/core
|
|
||||||
packages/next-auth/jwt
|
|
||||||
packages/next-auth/react
|
|
||||||
packages/next-auth/adapters.d.ts
|
|
||||||
packages/next-auth/adapters.js
|
|
||||||
packages/next-auth/index.d.ts
|
|
||||||
packages/next-auth/index.js
|
|
||||||
packages/next-auth/next
|
|
||||||
packages/next-auth/middleware.d.ts
|
|
||||||
packages/next-auth/middleware.js
|
|
||||||
|
|
||||||
# Development app
|
# Development app
|
||||||
apps/dev/src/css
|
apps/dev/src/css
|
||||||
apps/dev/prisma/migrations
|
apps/dev/prisma/migrations
|
||||||
apps/dev/typeorm
|
apps/dev/typeorm
|
||||||
|
apps/dev/nextjs-2
|
||||||
|
|
||||||
# VS
|
# VS
|
||||||
/.vs/slnx.sqlite-journal
|
/.vs/slnx.sqlite-journal
|
||||||
@@ -81,15 +71,16 @@ docs/.docusaurus
|
|||||||
docs/providers.json
|
docs/providers.json
|
||||||
|
|
||||||
# Core
|
# Core
|
||||||
packages/core/*.js
|
packages/core/src/providers/oauth-types.ts
|
||||||
packages/core/*.d.ts
|
|
||||||
packages/core/*.d.ts.map
|
|
||||||
packages/core/lib
|
packages/core/lib
|
||||||
packages/core/providers
|
packages/core/providers
|
||||||
packages/core/src/lib/pages/styles.ts
|
packages/core/src/lib/pages/styles.ts
|
||||||
docs/docs/reference/03-core
|
docs/docs/reference/core
|
||||||
docs/docs/reference/04-sveltekit
|
docs/docs/reference/sveltekit
|
||||||
|
docs/docs/reference/next-auth
|
||||||
|
|
||||||
|
# Next.js
|
||||||
|
packages/next-auth/lib
|
||||||
|
|
||||||
# SvelteKit
|
# SvelteKit
|
||||||
packages/frameworks-sveltekit/index.*
|
packages/frameworks-sveltekit/index.*
|
||||||
@@ -98,3 +89,7 @@ packages/frameworks-sveltekit/.svelte-kit
|
|||||||
packages/frameworks-sveltekit/package
|
packages/frameworks-sveltekit/package
|
||||||
packages/frameworks-sveltekit/vite.config.js.timestamp-*
|
packages/frameworks-sveltekit/vite.config.js.timestamp-*
|
||||||
packages/frameworks-sveltekit/vite.config.ts.timestamp-*
|
packages/frameworks-sveltekit/vite.config.ts.timestamp-*
|
||||||
|
|
||||||
|
# Adapters
|
||||||
|
|
||||||
|
docs/docs/reference/adapter
|
||||||
@@ -20,8 +20,8 @@ pnpm-lock.yaml
|
|||||||
|
|
||||||
.docusaurus
|
.docusaurus
|
||||||
build
|
build
|
||||||
docs/docs/reference/03-core
|
docs/docs/reference/core
|
||||||
docs/docs/reference/04-sveltekit
|
docs/docs/reference/sveltekit
|
||||||
static
|
static
|
||||||
docs/providers.json
|
docs/providers.json
|
||||||
|
|
||||||
@@ -40,10 +40,6 @@ packages/core/src/lib/pages/styles.ts
|
|||||||
packages/frameworks-sveltekit/package
|
packages/frameworks-sveltekit/package
|
||||||
packages/frameworks-sveltekit/vite.config.{js,ts}.timestamp-*
|
packages/frameworks-sveltekit/vite.config.{js,ts}.timestamp-*
|
||||||
|
|
||||||
# next-auth
|
|
||||||
packages/next-auth/src/providers/oauth-types.ts
|
|
||||||
packages/next-auth/css/index.css
|
|
||||||
|
|
||||||
|
|
||||||
# Adapters
|
# Adapters
|
||||||
.branches
|
.branches
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
// @ts-check
|
|
||||||
|
|
||||||
/** @type {import("prettier").Config} */
|
|
||||||
module.exports = {
|
|
||||||
semi: false,
|
|
||||||
singleQuote: false,
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: [
|
|
||||||
"apps/dev/pages/api/auth/[...nextauth].ts",
|
|
||||||
"docs/{sidebars,docusaurus.config}.js",
|
|
||||||
],
|
|
||||||
options: { printWidth: 150 },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ["**/*package.json"],
|
|
||||||
options: {
|
|
||||||
trailingComma: "none",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"files.exclude": {
|
"files.exclude": {
|
||||||
"packages/core/{lib,providers,*.js,*.d.ts,*.d.ts.map}": true,
|
"packages/core/{lib,providers,*.js,*.d.ts*}": true,
|
||||||
"packages/next-auth/{client,core,css,jwt,next,providers,react,utils,*.js,*.d.ts}": true
|
"packages/next-auth/{lib,*.js,*.d.ts*}": true,
|
||||||
},
|
},
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
"openInGitHub.remote.branch": "main"
|
"openInGitHub.remote.branch": "main"
|
||||||
}
|
}
|
||||||
58
apps/dev/nextjs-v4/.env.local.example
Normal file
58
apps/dev/nextjs-v4/.env.local.example
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Rename file to .env.local (or .env) and populate values
|
||||||
|
# to be able to run the dev app
|
||||||
|
|
||||||
|
NEXTAUTH_URL=http://localhost:3000
|
||||||
|
|
||||||
|
# You can use `openssl rand -hex 32` or
|
||||||
|
# https://generate-secret.vercel.app/32 to generate a secret.
|
||||||
|
# Note: Changing a secret may invalidate existing sessions
|
||||||
|
# and/or verification tokens.
|
||||||
|
NEXTAUTH_SECRET=secret
|
||||||
|
|
||||||
|
AUTH0_ID=
|
||||||
|
AUTH0_SECRET=
|
||||||
|
AUTH0_ISSUER=
|
||||||
|
|
||||||
|
KEYCLOAK_ID=
|
||||||
|
KEYCLOAK_SECRET=
|
||||||
|
KEYCLOAK_ISSUER=
|
||||||
|
|
||||||
|
IDS4_ID=
|
||||||
|
IDS4_SECRET=
|
||||||
|
IDS4_ISSUER=
|
||||||
|
|
||||||
|
GITHUB_ID=
|
||||||
|
GITHUB_SECRET=
|
||||||
|
|
||||||
|
TWITCH_ID=
|
||||||
|
TWITCH_SECRET=
|
||||||
|
|
||||||
|
TWITTER_ID=
|
||||||
|
TWITTER_SECRET=
|
||||||
|
|
||||||
|
LINE_ID=
|
||||||
|
LINE_SECRET=
|
||||||
|
|
||||||
|
TRAKT_ID=
|
||||||
|
TRAKT_SECRET=
|
||||||
|
|
||||||
|
# Example configuration for a Gmail account (will need SMTP enabled)
|
||||||
|
EMAIL_SERVER=smtps://user@gmail.com:password@smtp.gmail.com:465
|
||||||
|
EMAIL_FROM=user@gmail.com
|
||||||
|
|
||||||
|
# Note: If using with Prisma adapter, you need to use a `.env`
|
||||||
|
# file rather than a `.env.local` file to configure env vars.
|
||||||
|
# Postgres: DATABASE_URL=postgres://nextauth:password@127.0.0.1:5432/nextauth?synchronize=true
|
||||||
|
# MySQL: DATABASE_URL=mysql://nextauth:password@127.0.0.1:3306/nextauth?synchronize=true
|
||||||
|
# MongoDB: DATABASE_URL=mongodb://nextauth:password@127.0.0.1:27017/nextauth?synchronize=true
|
||||||
|
DATABASE_URL=
|
||||||
|
|
||||||
|
WIKIMEDIA_ID=
|
||||||
|
WIKIMEDIA_SECRET=
|
||||||
|
|
||||||
|
# Supabase Example Configuration
|
||||||
|
# Supabase Example Configuration
|
||||||
|
# NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
|
||||||
|
# SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSJ9.vI9obAHOGyVVKa3pD--kJlyxp-Z2zV9UUMAhKpNLAcU
|
||||||
|
# SUPABASE_JWT_SECRET=super-secret-jwt-token-with-at-least-32-characters-long
|
||||||
|
# NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs
|
||||||
4
apps/dev/nextjs-v4/.vscode/settings.json
vendored
Normal file
4
apps/dev/nextjs-v4/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"typescript.tsdk": "../../node_modules/.pnpm/typescript@4.8.4/node_modules/typescript/lib",
|
||||||
|
"typescript.enablePromptUseWorkspaceTsdk": true
|
||||||
|
}
|
||||||
6
apps/dev/nextjs-v4/README.md
Normal file
6
apps/dev/nextjs-v4/README.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# NextAuth.js Development App
|
||||||
|
|
||||||
|
This folder contains a Next.js app using NextAuth.js for local development. See the following section on how to start:
|
||||||
|
|
||||||
|
[Setting up local environment
|
||||||
|
](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md#setting-up-local-environment)
|
||||||
14
apps/dev/nextjs-v4/app/api/auth/[...nextauth]/route.ts
Normal file
14
apps/dev/nextjs-v4/app/api/auth/[...nextauth]/route.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import NextAuth, { type NextAuthOptions } from "next-auth"
|
||||||
|
import GitHub from "next-auth/providers/github"
|
||||||
|
|
||||||
|
export const authOptions: NextAuthOptions = {
|
||||||
|
providers: [
|
||||||
|
GitHub({
|
||||||
|
clientId: process.env.GITHUB_ID,
|
||||||
|
clientSecret: process.env.GITHUB_SECRET,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const handler = NextAuth(authOptions)
|
||||||
|
export { handler as GET, handler as POST }
|
||||||
12
apps/dev/nextjs-v4/app/layout.tsx
Normal file
12
apps/dev/nextjs-v4/app/layout.tsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<html>
|
||||||
|
<head></head>
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
||||||
6
apps/dev/nextjs-v4/app/server-component/page.tsx
Normal file
6
apps/dev/nextjs-v4/app/server-component/page.tsx
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { getServerSession } from "next-auth/next"
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
const session = await getServerSession()
|
||||||
|
return <pre>{JSON.stringify(session, null, 2)}</pre>
|
||||||
|
}
|
||||||
20
apps/dev/nextjs-v4/components/access-denied.js
Normal file
20
apps/dev/nextjs-v4/components/access-denied.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { signIn } from "next-auth/react"
|
||||||
|
|
||||||
|
export default function AccessDenied() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>Access Denied</h1>
|
||||||
|
<p>
|
||||||
|
<a
|
||||||
|
href="/api/auth/signin"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
signIn()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
You must be signed in to view this page
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
28
apps/dev/nextjs-v4/components/footer.js
Normal file
28
apps/dev/nextjs-v4/components/footer.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import Link from "next/link"
|
||||||
|
import styles from "./footer.module.css"
|
||||||
|
import packageJSON from "package.json"
|
||||||
|
|
||||||
|
export default function Footer() {
|
||||||
|
return (
|
||||||
|
<footer className={styles.footer}>
|
||||||
|
<hr />
|
||||||
|
<ul className={styles.navItems}>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<a href="https://next-auth.js.org">Documentation</a>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<a href="https://www.npmjs.com/package/next-auth">NPM</a>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<a href="https://github.com/nextauthjs/next-auth-example">GitHub</a>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<Link href="/policy">Policy</Link>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<em>{packageJSON.version}</em>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</footer>
|
||||||
|
)
|
||||||
|
}
|
||||||
14
apps/dev/nextjs-v4/components/footer.module.css
Normal file
14
apps/dev/nextjs-v4/components/footer.module.css
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
.footer {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navItems {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navItem {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
103
apps/dev/nextjs-v4/components/header.js
Normal file
103
apps/dev/nextjs-v4/components/header.js
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import Link from "next/link"
|
||||||
|
import { signIn, signOut, useSession } from "next-auth/react"
|
||||||
|
import styles from "./header.module.css"
|
||||||
|
|
||||||
|
// The approach used in this component shows how to built a sign in and sign out
|
||||||
|
// component that works on pages which support both client and server side
|
||||||
|
// rendering, and avoids any flash incorrect content on initial page load.
|
||||||
|
export default function Header() {
|
||||||
|
const { data: session, status } = useSession()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<header>
|
||||||
|
<noscript>
|
||||||
|
<style>{".nojs-show { opacity: 1; top: 0; }"}</style>
|
||||||
|
</noscript>
|
||||||
|
<div className={styles.signedInStatus}>
|
||||||
|
<p
|
||||||
|
className={`nojs-show ${
|
||||||
|
!session && status === "loading" ? styles.loading : styles.loaded
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{!session && (
|
||||||
|
<>
|
||||||
|
<span className={styles.notSignedInText}>
|
||||||
|
You are not signed in
|
||||||
|
</span>
|
||||||
|
<a
|
||||||
|
href="/api/auth/signin"
|
||||||
|
className={styles.buttonPrimary}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
signIn()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Sign in
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{session && (
|
||||||
|
<>
|
||||||
|
{session.user.image && (
|
||||||
|
<img src={session.user.image} className={styles.avatar} />
|
||||||
|
)}
|
||||||
|
<span className={styles.signedInText}>
|
||||||
|
<small>Signed in as</small>
|
||||||
|
<br />
|
||||||
|
<strong>{session.user.email} </strong>
|
||||||
|
{session.user.name ? `(${session.user.name})` : null}
|
||||||
|
</span>
|
||||||
|
<a
|
||||||
|
href="/api/auth/signout"
|
||||||
|
className={styles.button}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
signOut()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Sign out
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<nav>
|
||||||
|
<ul className={styles.navItems}>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<Link href="/">Home</Link>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<Link href="/client">Client</Link>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<Link href="/server">Server</Link>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<Link href="/protected">Protected</Link>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<Link href="/protected-ssr">Protected(SSR)</Link>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<Link href="/api-example">API</Link>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<Link href="/credentials">Credentials</Link>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<Link href="/email">Email</Link>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<Link href="/middleware-protected">Middleware protected</Link>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<Link href="/supabase-client-rls">Supabase RLS</Link>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<Link href="/supabase-ssr">Supabase RLS(SSR)</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
)
|
||||||
|
}
|
||||||
92
apps/dev/nextjs-v4/components/header.module.css
Normal file
92
apps/dev/nextjs-v4/components/header.module.css
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/* Set min-height to avoid page reflow while session loading */
|
||||||
|
.signedInStatus {
|
||||||
|
display: block;
|
||||||
|
min-height: 4rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading,
|
||||||
|
.loaded {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
opacity: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 0 0 .6rem .6rem;
|
||||||
|
padding: .6rem 1rem;
|
||||||
|
margin: 0;
|
||||||
|
background-color: rgba(0,0,0,.05);
|
||||||
|
transition: all 0.2s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
top: -2rem;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signedInText,
|
||||||
|
.notSignedInText {
|
||||||
|
position: absolute;
|
||||||
|
padding-top: .8rem;
|
||||||
|
left: 1rem;
|
||||||
|
right: 6.5rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
display: inherit;
|
||||||
|
z-index: 1;
|
||||||
|
line-height: 1.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signedInText {
|
||||||
|
padding-top: 0rem;
|
||||||
|
left: 4.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
border-radius: 2rem;
|
||||||
|
float: left;
|
||||||
|
height: 2.8rem;
|
||||||
|
width: 2.8rem;
|
||||||
|
background-color: white;
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button,
|
||||||
|
.buttonPrimary {
|
||||||
|
float: right;
|
||||||
|
margin-right: -.4rem;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: .3rem;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.4rem;
|
||||||
|
padding: .7rem .8rem;
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
background-color: transparent;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonPrimary {
|
||||||
|
background-color: #346df1;
|
||||||
|
border-color: #346df1;
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: .7rem 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonPrimary:hover {
|
||||||
|
box-shadow: inset 0 0 5rem rgba(0,0,0,0.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
.navItems {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navItem {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
14
apps/dev/nextjs-v4/components/layout.js
Normal file
14
apps/dev/nextjs-v4/components/layout.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import Header from 'components/header'
|
||||||
|
import Footer from 'components/footer'
|
||||||
|
|
||||||
|
export default function Layout ({ children }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
<main>
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
45
apps/dev/nextjs-v4/middleware.ts
Normal file
45
apps/dev/nextjs-v4/middleware.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
export { default } from "next-auth/middleware"
|
||||||
|
|
||||||
|
export const config = { matcher: ["/middleware-protected"] }
|
||||||
|
|
||||||
|
// Other ways to use this middleware
|
||||||
|
|
||||||
|
// import withAuth from "next-auth/middleware"
|
||||||
|
// import { withAuth } from "next-auth/middleware"
|
||||||
|
|
||||||
|
// export function middleware(req, ev) {
|
||||||
|
// return withAuth(req)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export function middleware(req, ev) {
|
||||||
|
// return withAuth(req, ev)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export function middleware(req, ev) {
|
||||||
|
// return withAuth(req, {
|
||||||
|
// callbacks: {
|
||||||
|
// authorized: ({ token }) => !!token,
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export default withAuth(function middleware(req, ev) {
|
||||||
|
// console.log(req.nextauth.token)
|
||||||
|
// })
|
||||||
|
|
||||||
|
// export default withAuth(
|
||||||
|
// function middleware(req, ev) {
|
||||||
|
// console.log(req, ev)
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// callbacks: {
|
||||||
|
// authorized: ({ token }) => token.name === "Balázs Orbán",
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
|
||||||
|
// export default withAuth({
|
||||||
|
// callbacks: {
|
||||||
|
// authorized: ({ token }) => !!token,
|
||||||
|
// },
|
||||||
|
// })
|
||||||
6
apps/dev/nextjs-v4/next-env.d.ts
vendored
Normal file
6
apps/dev/nextjs-v4/next-env.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/image-types/global" />
|
||||||
|
/// <reference types="next/navigation-types/compat/navigation" />
|
||||||
|
|
||||||
|
// NOTE: This file should not be edited
|
||||||
|
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||||
9
apps/dev/nextjs-v4/next.config.js
Normal file
9
apps/dev/nextjs-v4/next.config.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/** @type {import("next").NextConfig} */
|
||||||
|
module.exports = {
|
||||||
|
webpack(config) {
|
||||||
|
config.experiments = { ...config.experiments, topLevelAwait: true }
|
||||||
|
return config
|
||||||
|
},
|
||||||
|
experimental: { appDir: true },
|
||||||
|
typescript: { ignoreBuildErrors: true },
|
||||||
|
}
|
||||||
40
apps/dev/nextjs-v4/package.json
Normal file
40
apps/dev/nextjs-v4/package.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"name": "next-auth-app-v4",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "NextAuth.js Developer app",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rm -rf .next",
|
||||||
|
"dev": "next dev",
|
||||||
|
"lint": "next lint",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start",
|
||||||
|
"email": "fake-smtp-server",
|
||||||
|
"start:email": "pnpm email"
|
||||||
|
},
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@next-auth/fauna-adapter": "workspace:*",
|
||||||
|
"@next-auth/prisma-adapter": "workspace:*",
|
||||||
|
"@next-auth/supabase-adapter": "workspace:*",
|
||||||
|
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
||||||
|
"@prisma/client": "^3",
|
||||||
|
"@supabase/supabase-js": "^2.0.5",
|
||||||
|
"faunadb": "^4",
|
||||||
|
"next": "13.3.0",
|
||||||
|
"next-auth": "workspace:*",
|
||||||
|
"nodemailer": "^6",
|
||||||
|
"react": "^18",
|
||||||
|
"react-dom": "^18"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jsonwebtoken": "^8.5.5",
|
||||||
|
"@types/react": "^18.0.37",
|
||||||
|
"@types/react-dom": "^18.0.6",
|
||||||
|
"fake-smtp-server": "^0.8.0",
|
||||||
|
"pg": "^8.7.3",
|
||||||
|
"prisma": "^3",
|
||||||
|
"sqlite3": "^5.0.8",
|
||||||
|
"typeorm": "0.3.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
10
apps/dev/nextjs-v4/pages/_app.js
Normal file
10
apps/dev/nextjs-v4/pages/_app.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { SessionProvider } from "next-auth/react"
|
||||||
|
import "./styles.css"
|
||||||
|
|
||||||
|
export default function App({ Component, pageProps }) {
|
||||||
|
return (
|
||||||
|
<SessionProvider session={pageProps.session}>
|
||||||
|
<Component {...pageProps} />
|
||||||
|
</SessionProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,19 +1,17 @@
|
|||||||
import Layout from "../components/layout"
|
import Layout from '../components/layout'
|
||||||
|
|
||||||
export default function ApiExamplePage() {
|
export default function Page () {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<h1>API Example</h1>
|
<h1>API Example</h1>
|
||||||
<p>The examples below show responses from the example API endpoints.</p>
|
<p>The examples below show responses from the example API endpoints.</p>
|
||||||
<p>
|
<p><em>You must be signed in to see responses.</em></p>
|
||||||
<em>You must be signed in to see responses.</em>
|
|
||||||
</p>
|
|
||||||
<h2>Session</h2>
|
<h2>Session</h2>
|
||||||
<p>/api/examples/session</p>
|
<p>/api/examples/session</p>
|
||||||
<iframe src="/api/examples/session" />
|
<iframe src='/api/examples/session' />
|
||||||
<h2>JSON Web Token</h2>
|
<h2>JSON Web Token</h2>
|
||||||
<p>/api/examples/jwt</p>
|
<p>/api/examples/jwt</p>
|
||||||
<iframe src="/api/examples/jwt" />
|
<iframe src='/api/examples/jwt' />
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
132
apps/dev/nextjs-v4/pages/api/auth-old/[...nextauth].ts
Normal file
132
apps/dev/nextjs-v4/pages/api/auth-old/[...nextauth].ts
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
import NextAuth, { NextAuthOptions } from "next-auth"
|
||||||
|
|
||||||
|
// Providers
|
||||||
|
import Apple from "next-auth/providers/apple"
|
||||||
|
import Auth0 from "next-auth/providers/auth0"
|
||||||
|
import AzureAD from "next-auth/providers/azure-ad"
|
||||||
|
import AzureB2C from "next-auth/providers/azure-ad-b2c"
|
||||||
|
import BoxyHQSAML from "next-auth/providers/boxyhq-saml"
|
||||||
|
// import Cognito from "next-auth/providers/cognito"
|
||||||
|
import Credentials from "next-auth/providers/credentials"
|
||||||
|
import Discord from "next-auth/providers/discord"
|
||||||
|
import DuendeIDS6 from "next-auth/providers/duende-identity-server6"
|
||||||
|
// import Email from "next-auth/providers/email"
|
||||||
|
import Facebook from "next-auth/providers/facebook"
|
||||||
|
import Foursquare from "next-auth/providers/foursquare"
|
||||||
|
import Freshbooks from "next-auth/providers/freshbooks"
|
||||||
|
import GitHub from "next-auth/providers/github"
|
||||||
|
import Gitlab from "next-auth/providers/gitlab"
|
||||||
|
import Google from "next-auth/providers/google"
|
||||||
|
// import IDS4 from "next-auth/providers/identity-server4"
|
||||||
|
import Instagram from "next-auth/providers/instagram"
|
||||||
|
// import Keycloak from "next-auth/providers/keycloak"
|
||||||
|
import Line from "next-auth/providers/line"
|
||||||
|
import LinkedIn from "next-auth/providers/linkedin"
|
||||||
|
import Mailchimp from "next-auth/providers/mailchimp"
|
||||||
|
// import Okta from "next-auth/providers/okta"
|
||||||
|
import Osu from "next-auth/providers/osu"
|
||||||
|
import Patreon from "next-auth/providers/patreon"
|
||||||
|
import Slack from "next-auth/providers/slack"
|
||||||
|
import Spotify from "next-auth/providers/spotify"
|
||||||
|
import Trakt from "next-auth/providers/trakt"
|
||||||
|
import Twitch from "next-auth/providers/twitch"
|
||||||
|
import Twitter from "next-auth/providers/twitter"
|
||||||
|
import Vk from "next-auth/providers/vk"
|
||||||
|
import Wikimedia from "next-auth/providers/wikimedia"
|
||||||
|
import WorkOS from "next-auth/providers/workos"
|
||||||
|
|
||||||
|
// // Prisma
|
||||||
|
// import { PrismaClient } from "@prisma/client"
|
||||||
|
// import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||||
|
// const client = globalThis.prisma || new PrismaClient()
|
||||||
|
// if (process.env.NODE_ENV !== "production") globalThis.prisma = client
|
||||||
|
// const adapter = PrismaAdapter(client)
|
||||||
|
|
||||||
|
// // Fauna
|
||||||
|
// import { Client as FaunaClient } from "faunadb"
|
||||||
|
// import { FaunaAdapter } from "@next-auth/fauna-adapter"
|
||||||
|
// const opts = { secret: process.env.FAUNA_SECRET, domain: process.env.FAUNA_DOMAIN }
|
||||||
|
// const client = globalThis.fauna || new FaunaClient(opts)
|
||||||
|
// if (process.env.NODE_ENV !== "production") globalThis.fauna = client
|
||||||
|
// const adapter = FaunaAdapter(client)
|
||||||
|
|
||||||
|
// // TypeORM
|
||||||
|
// import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||||
|
// const adapter = TypeORMLegacyAdapter({
|
||||||
|
// type: "sqlite",
|
||||||
|
// name: "next-auth-test-memory",
|
||||||
|
// database: "./typeorm/dev.db",
|
||||||
|
// synchronize: true,
|
||||||
|
// })
|
||||||
|
|
||||||
|
// // Supabase
|
||||||
|
// import { SupabaseAdapter } from "@next-auth/supabase-adapter"
|
||||||
|
// const adapter = SupabaseAdapter({
|
||||||
|
// url: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||||
|
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
||||||
|
// })
|
||||||
|
|
||||||
|
export const authOptions: NextAuthOptions = {
|
||||||
|
// adapter,
|
||||||
|
// debug: process.env.NODE_ENV !== "production",
|
||||||
|
theme: {
|
||||||
|
logo: "https://next-auth.js.org/img/logo/logo-sm.png",
|
||||||
|
brandColor: "#1786fb",
|
||||||
|
},
|
||||||
|
providers: [
|
||||||
|
Credentials({
|
||||||
|
credentials: { password: { label: "Password", type: "password" } },
|
||||||
|
async authorize(credentials) {
|
||||||
|
if (credentials.password !== "pw") return null
|
||||||
|
return { name: "Fill Murray", email: "bill@fillmurray.com", image: "https://www.fillmurray.com/64/64", id: "1", foo: "" }
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Apple({ clientId: process.env.APPLE_ID, clientSecret: process.env.APPLE_SECRET }),
|
||||||
|
Auth0({ clientId: process.env.AUTH0_ID, clientSecret: process.env.AUTH0_SECRET, issuer: process.env.AUTH0_ISSUER }),
|
||||||
|
AzureAD({
|
||||||
|
clientId: process.env.AZURE_AD_CLIENT_ID,
|
||||||
|
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
|
||||||
|
tenantId: process.env.AZURE_AD_TENANT_ID,
|
||||||
|
}),
|
||||||
|
AzureB2C({ clientId: process.env.AZURE_B2C_ID, clientSecret: process.env.AZURE_B2C_SECRET, issuer: process.env.AZURE_B2C_ISSUER }),
|
||||||
|
BoxyHQSAML({ issuer: "https://jackson-demo.boxyhq.com", clientId: "tenant=boxyhq.com&product=saml-demo.boxyhq.com", clientSecret: "dummy" }),
|
||||||
|
// Cognito({ clientId: process.env.COGNITO_ID, clientSecret: process.env.COGNITO_SECRET, issuer: process.env.COGNITO_ISSUER }),
|
||||||
|
Discord({ clientId: process.env.DISCORD_ID, clientSecret: process.env.DISCORD_SECRET }),
|
||||||
|
DuendeIDS6({ clientId: "interactive.confidential", clientSecret: "secret", issuer: "https://demo.duendesoftware.com" }),
|
||||||
|
Facebook({ clientId: process.env.FACEBOOK_ID, clientSecret: process.env.FACEBOOK_SECRET }),
|
||||||
|
Foursquare({ clientId: process.env.FOURSQUARE_ID, clientSecret: process.env.FOURSQUARE_SECRET }),
|
||||||
|
Freshbooks({ clientId: process.env.FRESHBOOKS_ID, clientSecret: process.env.FRESHBOOKS_SECRET }),
|
||||||
|
GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET }),
|
||||||
|
Gitlab({ clientId: process.env.GITLAB_ID, clientSecret: process.env.GITLAB_SECRET }),
|
||||||
|
Google({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET }),
|
||||||
|
// IDS4({ clientId: process.env.IDS4_ID, clientSecret: process.env.IDS4_SECRET, issuer: process.env.IDS4_ISSUER }),
|
||||||
|
Instagram({ clientId: process.env.INSTAGRAM_ID, clientSecret: process.env.INSTAGRAM_SECRET }),
|
||||||
|
// Keycloak({ clientId: process.env.KEYCLOAK_ID, clientSecret: process.env.KEYCLOAK_SECRET, issuer: process.env.KEYCLOAK_ISSUER }),
|
||||||
|
Line({ clientId: process.env.LINE_ID, clientSecret: process.env.LINE_SECRET }),
|
||||||
|
LinkedIn({ clientId: process.env.LINKEDIN_ID, clientSecret: process.env.LINKEDIN_SECRET }),
|
||||||
|
Mailchimp({ clientId: process.env.MAILCHIMP_ID, clientSecret: process.env.MAILCHIMP_SECRET }),
|
||||||
|
// Okta({ clientId: process.env.OKTA_ID, clientSecret: process.env.OKTA_SECRET, issuer: process.env.OKTA_ISSUER }),
|
||||||
|
Osu({ clientId: process.env.OSU_CLIENT_ID, clientSecret: process.env.OSU_CLIENT_SECRET }),
|
||||||
|
Patreon({ clientId: process.env.PATREON_ID, clientSecret: process.env.PATREON_SECRET }),
|
||||||
|
Slack({ clientId: process.env.SLACK_ID, clientSecret: process.env.SLACK_SECRET }),
|
||||||
|
Spotify({ clientId: process.env.SPOTIFY_ID, clientSecret: process.env.SPOTIFY_SECRET }),
|
||||||
|
Trakt({ clientId: process.env.TRAKT_ID, clientSecret: process.env.TRAKT_SECRET }),
|
||||||
|
Twitch({ clientId: process.env.TWITCH_ID, clientSecret: process.env.TWITCH_SECRET }),
|
||||||
|
Twitter({ clientId: process.env.TWITTER_ID, clientSecret: process.env.TWITTER_SECRET }),
|
||||||
|
// TwitterLegacy({ clientId: process.env.TWITTER_LEGACY_ID, clientSecret: process.env.TWITTER_LEGACY_SECRET }),
|
||||||
|
Vk({ clientId: process.env.VK_ID, clientSecret: process.env.VK_SECRET }),
|
||||||
|
Wikimedia({ clientId: process.env.WIKIMEDIA_ID, clientSecret: process.env.WIKIMEDIA_SECRET }),
|
||||||
|
WorkOS({ clientId: process.env.WORKOS_ID, clientSecret: process.env.WORKOS_SECRET }),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authOptions.adapter) {
|
||||||
|
// TODO:
|
||||||
|
// authOptions.providers.unshift(
|
||||||
|
// // NOTE: You can start a fake e-mail server with `pnpm email`
|
||||||
|
// // and then go to `http://localhost:1080` in the browser
|
||||||
|
// Email({ server: "smtp://127.0.0.1:1025?tls.rejectUnauthorized=false" })
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NextAuth(authOptions)
|
||||||
7
apps/dev/nextjs-v4/pages/api/examples/jwt.js
Normal file
7
apps/dev/nextjs-v4/pages/api/examples/jwt.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// This is an example of how to read a JSON Web Token from an API route
|
||||||
|
import { getToken } from "next-auth/jwt"
|
||||||
|
|
||||||
|
export default async (req, res) => {
|
||||||
|
const token = await getToken({ req })
|
||||||
|
res.send(JSON.stringify(token, null, 2))
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
// This is an example of to protect an API route
|
// This is an example of to protect an API route
|
||||||
import { unstable_getServerSession } from "next-auth/next"
|
import { getServerSession } from "next-auth/next"
|
||||||
import { authOptions } from "../auth/[...nextauth]"
|
import { authOptions } from "../auth/[...nextauth]"
|
||||||
|
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
const session = await unstable_getServerSession(req, res, authOptions)
|
const session = await getServerSession(req, res, authOptions)
|
||||||
|
|
||||||
if (session) {
|
if (session) {
|
||||||
res.send({
|
res.send({
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// This is an example of how to access a session from an API route
|
// This is an example of how to access a session from an API route
|
||||||
import { unstable_getServerSession } from "next-auth/next"
|
import { getServerSession } from "next-auth/next"
|
||||||
import { authOptions } from "../auth/[...nextauth]"
|
import { authOptions } from "../auth/[...nextauth]"
|
||||||
|
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
const session = await unstable_getServerSession(req, res, authOptions)
|
const session = await getServerSession(req, res, authOptions)
|
||||||
res.json(session)
|
res.json(session)
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
// This is an example of how to query data from Supabase with RLS.
|
// This is an example of how to query data from Supabase with RLS.
|
||||||
// Learn more about Row Levele Security (RLS): https://supabase.com/docs/guides/auth/row-level-security
|
// Learn more about Row Levele Security (RLS): https://supabase.com/docs/guides/auth/row-level-security
|
||||||
import { unstable_getServerSession } from "next-auth/next"
|
import { getServerSession } from "next-auth/next"
|
||||||
import { authOptions } from "../auth/[...nextauth]"
|
import { authOptions } from "../auth/[...nextauth]"
|
||||||
import { createClient } from "@supabase/supabase-js"
|
import { createClient } from "@supabase/supabase-js"
|
||||||
|
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
const session = await unstable_getServerSession(req, res, authOptions)
|
const session = await getServerSession(req, res, authOptions)
|
||||||
|
|
||||||
if (!session)
|
if (!session)
|
||||||
return res.send(JSON.stringify({ error: "No session!" }, null, 2))
|
return res.send(JSON.stringify({ error: "No session!" }, null, 2))
|
||||||
22
apps/dev/nextjs-v4/pages/client.js
Normal file
22
apps/dev/nextjs-v4/pages/client.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import Layout from '../components/layout'
|
||||||
|
|
||||||
|
export default function Page () {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<h1>Client Side Rendering</h1>
|
||||||
|
<p>
|
||||||
|
This page uses the <strong>useSession()</strong> React Hook in the <strong></Header></strong> component.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The <strong>useSession()</strong> React Hook easy to use and allows pages to render very quickly.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The advantage of this approach is that session state is shared between pages by using the <strong>Provider</strong> in <strong>_app.js</strong> so
|
||||||
|
that navigation between pages using <strong>useSession()</strong> is very fast.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The disadvantage of <strong>useSession()</strong> is that it requires client side JavaScript.
|
||||||
|
</p>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
67
apps/dev/nextjs-v4/pages/credentials.js
Normal file
67
apps/dev/nextjs-v4/pages/credentials.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
// eslint-disable-next-line no-use-before-define
|
||||||
|
import * as React from "react"
|
||||||
|
import { signIn, signOut, useSession } from "next-auth/react"
|
||||||
|
import Layout from "components/layout"
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
const [response, setResponse] = React.useState(null)
|
||||||
|
const handleLogin = (options) => async () => {
|
||||||
|
if (options.redirect) {
|
||||||
|
return signIn("credentials", options)
|
||||||
|
}
|
||||||
|
const response = await signIn("credentials", options)
|
||||||
|
setResponse(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleLogout = (options) => async () => {
|
||||||
|
if (options.redirect) {
|
||||||
|
return signOut(options)
|
||||||
|
}
|
||||||
|
const response = await signOut(options)
|
||||||
|
setResponse(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data: session } = useSession()
|
||||||
|
|
||||||
|
if (session) {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<h1>Test different flows for Credentials logout</h1>
|
||||||
|
<span className="spacing">Default:</span>
|
||||||
|
<button onClick={handleLogout({ redirect: true })}>Logout</button>
|
||||||
|
<br />
|
||||||
|
<span className="spacing">No redirect:</span>
|
||||||
|
<button onClick={handleLogout({ redirect: false })}>Logout</button>
|
||||||
|
<br />
|
||||||
|
<p>Response:</p>
|
||||||
|
<pre style={{ background: "#eee", padding: 16 }}>
|
||||||
|
{JSON.stringify(response, null, 2)}
|
||||||
|
</pre>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<h1>Test different flows for Credentials login</h1>
|
||||||
|
<span className="spacing">Default:</span>
|
||||||
|
<button onClick={handleLogin({ redirect: true, password: "password" })}>
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
<br />
|
||||||
|
<span className="spacing">No redirect:</span>
|
||||||
|
<button onClick={handleLogin({ redirect: false, password: "password" })}>
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
<br />
|
||||||
|
<span className="spacing">No redirect, wrong password:</span>
|
||||||
|
<button onClick={handleLogin({ redirect: false, password: "" })}>
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
<p>Response:</p>
|
||||||
|
<pre style={{ background: "#eee", padding: 16 }}>
|
||||||
|
{JSON.stringify(response, null, 2)}
|
||||||
|
</pre>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
80
apps/dev/nextjs-v4/pages/email.js
Normal file
80
apps/dev/nextjs-v4/pages/email.js
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
// eslint-disable-next-line no-use-before-define
|
||||||
|
import * as React from "react"
|
||||||
|
import { signIn, signOut, useSession } from "next-auth/react"
|
||||||
|
import Layout from "components/layout"
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
const [response, setResponse] = React.useState(null)
|
||||||
|
const [email, setEmail] = React.useState("")
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
setEmail(event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleLogin = (options) => async (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
if (options.redirect) {
|
||||||
|
return signIn("email", options)
|
||||||
|
}
|
||||||
|
const response = await signIn("email", options)
|
||||||
|
setResponse(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleLogout = (options) => async (event) => {
|
||||||
|
if (options.redirect) {
|
||||||
|
return signOut(options)
|
||||||
|
}
|
||||||
|
const response = await signOut(options)
|
||||||
|
setResponse(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data: session } = useSession()
|
||||||
|
|
||||||
|
if (session) {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<h1>Test different flows for Email logout</h1>
|
||||||
|
<span className="spacing">Default:</span>
|
||||||
|
<button onClick={handleLogout({ redirect: true })}>Logout</button>
|
||||||
|
<br />
|
||||||
|
<span className="spacing">No redirect:</span>
|
||||||
|
<button onClick={handleLogout({ redirect: false })}>Logout</button>
|
||||||
|
<br />
|
||||||
|
<p>Response:</p>
|
||||||
|
<pre style={{ background: "#eee", padding: 16 }}>
|
||||||
|
{JSON.stringify(response, null, 2)}
|
||||||
|
</pre>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<h1>Test different flows for Email login</h1>
|
||||||
|
<label className="spacing">
|
||||||
|
Email address:{" "}
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="email"
|
||||||
|
name="email"
|
||||||
|
value={email}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<br />
|
||||||
|
<form onSubmit={handleLogin({ redirect: true, email })}>
|
||||||
|
<span className="spacing">Default:</span>
|
||||||
|
<button type="submit">Sign in with Email</button>
|
||||||
|
</form>
|
||||||
|
<form onSubmit={handleLogin({ redirect: false, email })}>
|
||||||
|
<span className="spacing">No redirect:</span>
|
||||||
|
<button type="submit">Sign in with Email</button>
|
||||||
|
</form>
|
||||||
|
<p>Response:</p>
|
||||||
|
<pre style={{ background: "#eee", padding: 16 }}>
|
||||||
|
{JSON.stringify(response, null, 2)}
|
||||||
|
</pre>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
12
apps/dev/nextjs-v4/pages/index.js
Normal file
12
apps/dev/nextjs-v4/pages/index.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import Layout from 'components/layout'
|
||||||
|
|
||||||
|
export default function Page () {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<h1>NextAuth.js Example</h1>
|
||||||
|
<p>
|
||||||
|
This is an example site to demonstrate how to use <a href='https://next-auth.js.org'>NextAuth.js</a> for authentication.
|
||||||
|
</p>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
9
apps/dev/nextjs-v4/pages/middleware-protected/index.js
Normal file
9
apps/dev/nextjs-v4/pages/middleware-protected/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Layout from "components/layout"
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<h1>Page protected by Middleware</h1>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
30
apps/dev/nextjs-v4/pages/policy.js
Normal file
30
apps/dev/nextjs-v4/pages/policy.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import Layout from '../components/layout'
|
||||||
|
|
||||||
|
export default function Page () {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<p>
|
||||||
|
This is an example site to demonstrate how to use <a href='https://next-auth.js.org'>NextAuth.js</a> for authentication.
|
||||||
|
</p>
|
||||||
|
<h2>Terms of Service</h2>
|
||||||
|
<p>
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
</p>
|
||||||
|
<h2>Privacy Policy</h2>
|
||||||
|
<p>
|
||||||
|
This site uses JSON Web Tokens and an in-memory database which resets every ~2 hours.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Data provided to this site is exclusively used to support signing in
|
||||||
|
and is not passed to any third party services, other than via SMTP or OAuth for the
|
||||||
|
purposes of authentication.
|
||||||
|
</p>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
48
apps/dev/nextjs-v4/pages/protected-ssr.js
Normal file
48
apps/dev/nextjs-v4/pages/protected-ssr.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// This is an example of how to protect content using server rendering
|
||||||
|
import { getServerSession } from "next-auth/next"
|
||||||
|
import { authOptions } from "./api/auth/[...nextauth]"
|
||||||
|
import Layout from "../components/layout"
|
||||||
|
import AccessDenied from "../components/access-denied"
|
||||||
|
|
||||||
|
export default function Page({ content, session }) {
|
||||||
|
// If no session exists, display access denied message
|
||||||
|
if (!session) {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<AccessDenied />
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If session exists, display content
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<h1>Protected Page</h1>
|
||||||
|
<p>
|
||||||
|
<strong>{content}</strong>
|
||||||
|
</p>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getServerSideProps(context) {
|
||||||
|
const session = await getServerSession(context.req, context.res, authOptions)
|
||||||
|
let content = null
|
||||||
|
|
||||||
|
if (session) {
|
||||||
|
const hostname = process.env.NEXTAUTH_URL || "http://localhost:3000"
|
||||||
|
const options = { headers: { cookie: context.req.headers.cookie } }
|
||||||
|
const res = await fetch(`${hostname}/api/examples/protected`, options)
|
||||||
|
const json = await res.json()
|
||||||
|
if (json.content) {
|
||||||
|
content = json.content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
session,
|
||||||
|
content,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
import { useState, useEffect } from "react"
|
import { useState, useEffect } from "react"
|
||||||
import { useSession } from "next-auth/react"
|
import { useSession } from "next-auth/react"
|
||||||
import Layout from "../components/layout"
|
import Layout from "../components/layout"
|
||||||
import AccessDenied from "../components/access-denied"
|
|
||||||
|
|
||||||
export default function ProtectedPage() {
|
export default function Page() {
|
||||||
const { data: session } = useSession()
|
const { status } = useSession({
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
const [content, setContent] = useState()
|
const [content, setContent] = useState()
|
||||||
|
|
||||||
// Fetch content from protected route
|
// Fetch content from protected route
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (status === "loading") return
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const res = await fetch("/api/examples/protected")
|
const res = await fetch("/api/examples/protected")
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
@@ -17,23 +19,16 @@ export default function ProtectedPage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchData()
|
fetchData()
|
||||||
}, [session])
|
}, [status])
|
||||||
|
|
||||||
// If no session exists, display access denied message
|
if (status === "loading") return <Layout>Loading...</Layout>
|
||||||
if (!session) {
|
|
||||||
return (
|
|
||||||
<Layout>
|
|
||||||
<AccessDenied />
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If session exists, display content
|
// If session exists, display content
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<h1>Protected Page</h1>
|
<h1>Protected Page</h1>
|
||||||
<p>
|
<p>
|
||||||
<strong>{content ?? "\u00a0"}</strong>
|
<strong>{content}</strong>
|
||||||
</p>
|
</p>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
46
apps/dev/nextjs-v4/pages/server.js
Normal file
46
apps/dev/nextjs-v4/pages/server.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { getServerSession } from "next-auth/next"
|
||||||
|
import Layout from "../components/layout"
|
||||||
|
import { authOptions } from "./api/auth/[...nextauth]"
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
// As this page uses Server Side Rendering, the `session` will be already
|
||||||
|
// populated on render without needing to go through a loading stage.
|
||||||
|
// This is possible because of the shared context configured in `_app.js` that
|
||||||
|
// is used by `useSession()`.
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<h1>Server Side Rendering</h1>
|
||||||
|
<p>
|
||||||
|
This page uses the <strong>getServerSession()</strong> method in{" "}
|
||||||
|
<strong>getServerSideProps()</strong>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Using <strong>getServerSession()</strong> in{" "}
|
||||||
|
<strong>getServerSideProps()</strong> is currently the recommended
|
||||||
|
approach, although the API may still change, if you need to support
|
||||||
|
Server Side Rendering with authentication.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Using <strong>getSession()</strong> is still recommended on the client.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The advantage of Server Side Rendering is this page does not require
|
||||||
|
client side JavaScript.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The disadvantage of Server Side Rendering is that this page is slower to
|
||||||
|
render.
|
||||||
|
</p>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export the `session` prop to use sessions with Server Side Rendering
|
||||||
|
export async function getServerSideProps(context) {
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
session: await getServerSession(context.req, context.res, authOptions),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
32
apps/dev/nextjs-v4/pages/styles.css
Normal file
32
apps/dev/nextjs-v4/pages/styles.css
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
body {
|
||||||
|
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
||||||
|
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
|
||||||
|
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
padding: 0 1rem 1rem 1rem;
|
||||||
|
max-width: 680px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: #fff;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
li,
|
||||||
|
p {
|
||||||
|
line-height: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
background: #ccc;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
height: 10rem;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: .5rem;
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ export default function Page() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (session) {
|
if (session) {
|
||||||
|
console.log(session)
|
||||||
// User is logged in, let's fetch their data.
|
// User is logged in, let's fetch their data.
|
||||||
const { supabaseAccessToken } = session
|
const { supabaseAccessToken } = session
|
||||||
const supabase = createClient(
|
const supabase = createClient(
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// This is an example of how to protect content using server rendering
|
// This is an example of how to protect content using server rendering
|
||||||
// and fetching data from Supabase with RLS enabled.
|
// and fetching data from Supabase with RLS enabled.
|
||||||
import { unstable_getServerSession } from "next-auth/next"
|
import { getServerSession } from "next-auth/next"
|
||||||
import { authOptions } from "./api/auth/[...nextauth]"
|
import { authOptions } from "./api/auth/[...nextauth]"
|
||||||
import { createClient } from "@supabase/supabase-js"
|
import { createClient } from "@supabase/supabase-js"
|
||||||
import Layout from "../components/layout"
|
import Layout from "../components/layout"
|
||||||
@@ -27,11 +27,7 @@ export default function Page({ data, session }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getServerSideProps(context) {
|
export async function getServerSideProps(context) {
|
||||||
const session = await unstable_getServerSession(
|
const session = await getServerSession(context.req, context.res, authOptions)
|
||||||
context.req,
|
|
||||||
context.res,
|
|
||||||
authOptions
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!session)
|
if (!session)
|
||||||
return {
|
return {
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Account" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"type" TEXT NOT NULL,
|
||||||
|
"provider" TEXT NOT NULL,
|
||||||
|
"providerAccountId" TEXT NOT NULL,
|
||||||
|
"refresh_token" TEXT,
|
||||||
|
"access_token" TEXT,
|
||||||
|
"expires_at" INTEGER,
|
||||||
|
"token_type" TEXT,
|
||||||
|
"scope" TEXT,
|
||||||
|
"id_token" TEXT,
|
||||||
|
"session_state" TEXT,
|
||||||
|
"oauth_token_secret" TEXT,
|
||||||
|
"oauth_token" TEXT,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL,
|
||||||
|
CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Session" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"sessionToken" TEXT NOT NULL,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"expires" DATETIME NOT NULL,
|
||||||
|
CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "User" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"name" TEXT,
|
||||||
|
"email" TEXT,
|
||||||
|
"emailVerified" DATETIME,
|
||||||
|
"image" TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "VerificationToken" (
|
||||||
|
"identifier" TEXT NOT NULL,
|
||||||
|
"token" TEXT NOT NULL,
|
||||||
|
"expires" DATETIME NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token");
|
||||||
3
apps/dev/nextjs-v4/prisma/migrations/migration_lock.toml
Normal file
3
apps/dev/nextjs-v4/prisma/migrations/migration_lock.toml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Please do not edit this file manually
|
||||||
|
# It should be added in your version-control system (i.e. Git)
|
||||||
|
provider = "sqlite"
|
||||||
57
apps/dev/nextjs-v4/prisma/schema.prisma
Normal file
57
apps/dev/nextjs-v4/prisma/schema.prisma
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
datasource db {
|
||||||
|
provider = "sqlite"
|
||||||
|
url = "file:./dev.db"
|
||||||
|
}
|
||||||
|
|
||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
}
|
||||||
|
|
||||||
|
model Account {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
userId String
|
||||||
|
type String
|
||||||
|
provider String
|
||||||
|
providerAccountId String
|
||||||
|
refresh_token String?
|
||||||
|
access_token String?
|
||||||
|
expires_at Int?
|
||||||
|
token_type String?
|
||||||
|
scope String?
|
||||||
|
id_token String?
|
||||||
|
session_state String?
|
||||||
|
oauth_token_secret String?
|
||||||
|
oauth_token String?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
|
||||||
|
@@unique([provider, providerAccountId])
|
||||||
|
}
|
||||||
|
|
||||||
|
model Session {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
sessionToken String @unique
|
||||||
|
userId String
|
||||||
|
expires DateTime
|
||||||
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
}
|
||||||
|
|
||||||
|
model User {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String?
|
||||||
|
email String? @unique
|
||||||
|
emailVerified DateTime?
|
||||||
|
image String?
|
||||||
|
accounts Account[]
|
||||||
|
sessions Session[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model VerificationToken {
|
||||||
|
identifier String
|
||||||
|
token String @unique
|
||||||
|
expires DateTime
|
||||||
|
|
||||||
|
@@unique([identifier, token])
|
||||||
|
}
|
||||||
39
apps/dev/nextjs-v4/tsconfig.json
Normal file
39
apps/dev/nextjs-v4/tsconfig.json
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "esnext",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": false,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"incremental": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"baseUrl": ".",
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"strictNullChecks": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".next/types/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"jest.config.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
20
apps/dev/nextjs-v4/types/nextauth.d.ts
vendored
Normal file
20
apps/dev/nextjs-v4/types/nextauth.d.ts
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
import NextAuth from "next-auth"
|
||||||
|
|
||||||
|
declare module "next-auth" {
|
||||||
|
/**
|
||||||
|
* Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
|
||||||
|
*/
|
||||||
|
interface Session {
|
||||||
|
// A JWT which can be used as Authorization header with supabase-js for RLS.
|
||||||
|
supabaseAccessToken?: string
|
||||||
|
user: {
|
||||||
|
/** The user's postal address. */
|
||||||
|
address: string
|
||||||
|
} & User
|
||||||
|
}
|
||||||
|
|
||||||
|
interface User {
|
||||||
|
foo: string
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,20 +9,39 @@ NEXTAUTH_URL=http://localhost:3000
|
|||||||
# and/or verification tokens.
|
# and/or verification tokens.
|
||||||
NEXTAUTH_SECRET=secret
|
NEXTAUTH_SECRET=secret
|
||||||
|
|
||||||
|
ASGARDEO_CLIENT_ID=
|
||||||
|
ASGARDEO_CLIENT_SECRET=
|
||||||
|
ASGARDEO_ISSUER=
|
||||||
|
|
||||||
AUTH0_ID=
|
AUTH0_ID=
|
||||||
AUTH0_SECRET=
|
AUTH0_SECRET=
|
||||||
AUTH0_ISSUER=
|
AUTH0_ISSUER=
|
||||||
|
|
||||||
KEYCLOAK_ID=
|
# Beyond Identity Provider
|
||||||
KEYCLOAK_SECRET=
|
BEYOND_IDENTITY_CLIENT_ID=
|
||||||
KEYCLOAK_ISSUER=
|
BEYOND_IDENTITY_CLIENT_SECRET=
|
||||||
|
BEYOND_IDENTITY_ISSUER=
|
||||||
|
|
||||||
|
GITHUB_ID=
|
||||||
|
GITHUB_SECRET=
|
||||||
|
|
||||||
|
NOTION_ID=
|
||||||
|
NOTION_SECRET=
|
||||||
|
NOTION_REDIRECT_URI=
|
||||||
|
|
||||||
IDS4_ID=
|
IDS4_ID=
|
||||||
IDS4_SECRET=
|
IDS4_SECRET=
|
||||||
IDS4_ISSUER=
|
IDS4_ISSUER=
|
||||||
|
|
||||||
GITHUB_ID=
|
KEYCLOAK_ID=
|
||||||
GITHUB_SECRET=
|
KEYCLOAK_SECRET=
|
||||||
|
KEYCLOAK_ISSUER=
|
||||||
|
|
||||||
|
LINE_ID=
|
||||||
|
LINE_SECRET=
|
||||||
|
|
||||||
|
TRAKT_ID=
|
||||||
|
TRAKT_SECRET=
|
||||||
|
|
||||||
TWITCH_ID=
|
TWITCH_ID=
|
||||||
TWITCH_SECRET=
|
TWITCH_SECRET=
|
||||||
@@ -30,11 +49,12 @@ TWITCH_SECRET=
|
|||||||
TWITTER_ID=
|
TWITTER_ID=
|
||||||
TWITTER_SECRET=
|
TWITTER_SECRET=
|
||||||
|
|
||||||
LINE_ID=
|
WIKIMEDIA_ID=
|
||||||
LINE_SECRET=
|
WIKIMEDIA_SECRET=
|
||||||
|
|
||||||
TRAKT_ID=
|
# Yandex OAuth. new app -> https://oauth.yandex.com/client/new/id
|
||||||
TRAKT_SECRET=
|
YANDEX_ID=
|
||||||
|
YANDEX_SECRET=
|
||||||
|
|
||||||
# Example configuration for a Gmail account (will need SMTP enabled)
|
# Example configuration for a Gmail account (will need SMTP enabled)
|
||||||
EMAIL_SERVER=smtps://user@gmail.com:password@smtp.gmail.com:465
|
EMAIL_SERVER=smtps://user@gmail.com:password@smtp.gmail.com:465
|
||||||
@@ -47,12 +67,9 @@ EMAIL_FROM=user@gmail.com
|
|||||||
# MongoDB: DATABASE_URL=mongodb://nextauth:password@127.0.0.1:27017/nextauth?synchronize=true
|
# MongoDB: DATABASE_URL=mongodb://nextauth:password@127.0.0.1:27017/nextauth?synchronize=true
|
||||||
DATABASE_URL=
|
DATABASE_URL=
|
||||||
|
|
||||||
WIKIMEDIA_ID=
|
|
||||||
WIKIMEDIA_SECRET=
|
|
||||||
|
|
||||||
# Supabase Example Configuration
|
# Supabase Example Configuration
|
||||||
# Supabase Example Configuration
|
# Supabase Example Configuration
|
||||||
# NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
|
# NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
|
||||||
# SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSJ9.vI9obAHOGyVVKa3pD--kJlyxp-Z2zV9UUMAhKpNLAcU
|
# SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSJ9.vI9obAHOGyVVKa3pD--kJlyxp-Z2zV9UUMAhKpNLAcU
|
||||||
# SUPABASE_JWT_SECRET=super-secret-jwt-token-with-at-least-32-characters-long
|
# SUPABASE_JWT_SECRET=super-secret-jwt-token-with-at-least-32-characters-long
|
||||||
# NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs
|
# NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs
|
||||||
|
|||||||
4
apps/dev/nextjs/.gitignore
vendored
Normal file
4
apps/dev/nextjs/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
node_modules/
|
||||||
|
/test-results/
|
||||||
|
/playwright-report/
|
||||||
|
/playwright/.cache/
|
||||||
3
apps/dev/nextjs/app/api/auth/[...nextauth]/route.ts
Normal file
3
apps/dev/nextjs/app/api/auth/[...nextauth]/route.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { handlers } from "auth"
|
||||||
|
export const { GET, POST } = handlers
|
||||||
|
export const runtime = "edge"
|
||||||
10
apps/dev/nextjs/app/api/protected/route.ts
Normal file
10
apps/dev/nextjs/app/api/protected/route.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { auth } from "auth"
|
||||||
|
import { NextResponse } from "next/server"
|
||||||
|
|
||||||
|
export const GET = auth(function GET(req) {
|
||||||
|
if (req.auth) {
|
||||||
|
return NextResponse.json(req.auth)
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json({ message: "Not authenticated" }, { status: 401 })
|
||||||
|
})
|
||||||
@@ -1,6 +1,37 @@
|
|||||||
import { unstable_getServerSession } from "next-auth/next"
|
import { auth } from "auth"
|
||||||
|
import { cookies, headers } from "next/headers"
|
||||||
|
|
||||||
|
function SignIn({ id, children }: any) {
|
||||||
|
const $cookies = cookies()
|
||||||
|
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||||
|
return (
|
||||||
|
<form action={`/api/auth/signin/${id}`} method="post">
|
||||||
|
<button type="submit">{children}</button>
|
||||||
|
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SignOut({ children }: any) {
|
||||||
|
const $cookies = cookies()
|
||||||
|
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||||
|
return (
|
||||||
|
<form action="/api/auth/signout" method="post">
|
||||||
|
<button type="submit">{children}</button>
|
||||||
|
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default async function Page() {
|
export default async function Page() {
|
||||||
const session = await unstable_getServerSession()
|
const session = await auth(headers())
|
||||||
return <pre>{JSON.stringify(session, null, 2)}</pre>
|
if (session) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<pre>{JSON.stringify(session, null, 2)}</pre>
|
||||||
|
<SignOut>Sign out</SignOut>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return <SignIn id="github">Sign in with github</SignIn>
|
||||||
}
|
}
|
||||||
|
|||||||
21
apps/dev/nextjs/auth.ts
Normal file
21
apps/dev/nextjs/auth.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { NextAuth } from "next-auth"
|
||||||
|
import GitHub from "@auth/core/providers/github"
|
||||||
|
|
||||||
|
export const { handlers, auth } = NextAuth({
|
||||||
|
providers: [GitHub],
|
||||||
|
callbacks: {
|
||||||
|
async authorized({ request, auth }) {
|
||||||
|
// if (request.method === "POST") {
|
||||||
|
// const [, token] = request.headers.get("Authorization")?.split(" ")
|
||||||
|
// const valid = validateToken(token)
|
||||||
|
// // If the request has a valid auth token, it is authorized
|
||||||
|
// if (valid) return true
|
||||||
|
// return NextResponse.json("Invalid auth token", { status: 401 })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Logged in users are authorized, otherwise, will redirect to login
|
||||||
|
// You could also return a custom redirect instead of the sign-in page
|
||||||
|
return !!auth
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import styles from "./footer.module.css"
|
import styles from "./footer.module.css"
|
||||||
import packageJSON from "package.json"
|
import packageJSON from "next-auth/package.json"
|
||||||
|
|
||||||
export default function Footer() {
|
export default function Footer() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { signIn, signOut, useSession } from "next-auth/react"
|
import { useSession } from "next-auth/react"
|
||||||
import styles from "./header.module.css"
|
import styles from "./header.module.css"
|
||||||
|
|
||||||
// The approach used in this component shows how to built a sign in and sign out
|
// The approach used in this component shows how to built a sign in and sign out
|
||||||
@@ -24,14 +24,7 @@ export default function Header() {
|
|||||||
<span className={styles.notSignedInText}>
|
<span className={styles.notSignedInText}>
|
||||||
You are not signed in
|
You are not signed in
|
||||||
</span>
|
</span>
|
||||||
<a
|
<a href="/api/auth/signin" className={styles.buttonPrimary}>
|
||||||
href="/api/auth/signin"
|
|
||||||
className={styles.buttonPrimary}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault()
|
|
||||||
signIn()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Sign in
|
Sign in
|
||||||
</a>
|
</a>
|
||||||
</>
|
</>
|
||||||
@@ -47,14 +40,7 @@ export default function Header() {
|
|||||||
<strong>{session.user.email} </strong>
|
<strong>{session.user.email} </strong>
|
||||||
{session.user.name ? `(${session.user.name})` : null}
|
{session.user.name ? `(${session.user.name})` : null}
|
||||||
</span>
|
</span>
|
||||||
<a
|
<a href="/api/auth/signout" className={styles.button}>
|
||||||
href="/api/auth/signout"
|
|
||||||
className={styles.button}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault()
|
|
||||||
signOut()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Sign out
|
Sign out
|
||||||
</a>
|
</a>
|
||||||
</>
|
</>
|
||||||
@@ -90,12 +76,6 @@ export default function Header() {
|
|||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<Link href="/middleware-protected">Middleware protected</Link>
|
<Link href="/middleware-protected">Middleware protected</Link>
|
||||||
</li>
|
</li>
|
||||||
<li className={styles.navItem}>
|
|
||||||
<Link href="/supabase-client-rls">Supabase RLS</Link>
|
|
||||||
</li>
|
|
||||||
<li className={styles.navItem}>
|
|
||||||
<Link href="/supabase-ssr">Supabase RLS(SSR)</Link>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -1,45 +1,10 @@
|
|||||||
export { default } from "next-auth/middleware"
|
// export { auth as default } from "auth"
|
||||||
|
import { auth } from "auth"
|
||||||
|
import { NextResponse } from "next/server"
|
||||||
|
|
||||||
|
export default auth((req) => {
|
||||||
|
if (req.auth) return NextResponse.json(req.auth)
|
||||||
|
return NextResponse.json("Not authorized", { status: 401 })
|
||||||
|
})
|
||||||
|
|
||||||
export const config = { matcher: ["/middleware-protected"] }
|
export const config = { matcher: ["/middleware-protected"] }
|
||||||
|
|
||||||
// Other ways to use this middleware
|
|
||||||
|
|
||||||
// import withAuth from "next-auth/middleware"
|
|
||||||
// import { withAuth } from "next-auth/middleware"
|
|
||||||
|
|
||||||
// export function middleware(req, ev) {
|
|
||||||
// return withAuth(req)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export function middleware(req, ev) {
|
|
||||||
// return withAuth(req, ev)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export function middleware(req, ev) {
|
|
||||||
// return withAuth(req, {
|
|
||||||
// callbacks: {
|
|
||||||
// authorized: ({ token }) => !!token,
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export default withAuth(function middleware(req, ev) {
|
|
||||||
// console.log(req.nextauth.token)
|
|
||||||
// })
|
|
||||||
|
|
||||||
// export default withAuth(
|
|
||||||
// function middleware(req, ev) {
|
|
||||||
// console.log(req, ev)
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// callbacks: {
|
|
||||||
// authorized: ({ token }) => token.name === "Balázs Orbán",
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
|
|
||||||
// export default withAuth({
|
|
||||||
// callbacks: {
|
|
||||||
// authorized: ({ token }) => !!token,
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
|
|||||||
1
apps/dev/nextjs/next-env.d.ts
vendored
1
apps/dev/nextjs/next-env.d.ts
vendored
@@ -1,5 +1,6 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
|
/// <reference types="next/navigation-types/compat/navigation" />
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||||
|
|||||||
@@ -9,10 +9,13 @@
|
|||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"email": "fake-smtp-server",
|
"email": "fake-smtp-server",
|
||||||
"start:email": "pnpm email"
|
"start:email": "pnpm email",
|
||||||
|
"e2e": "pnpm dlx playwright test"
|
||||||
},
|
},
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@auth/core": "workspace:*",
|
||||||
|
"next-auth": "workspace:*",
|
||||||
"@next-auth/fauna-adapter": "workspace:*",
|
"@next-auth/fauna-adapter": "workspace:*",
|
||||||
"@next-auth/prisma-adapter": "workspace:*",
|
"@next-auth/prisma-adapter": "workspace:*",
|
||||||
"@next-auth/supabase-adapter": "workspace:*",
|
"@next-auth/supabase-adapter": "workspace:*",
|
||||||
@@ -20,17 +23,18 @@
|
|||||||
"@prisma/client": "^3",
|
"@prisma/client": "^3",
|
||||||
"@supabase/supabase-js": "^2.0.5",
|
"@supabase/supabase-js": "^2.0.5",
|
||||||
"faunadb": "^4",
|
"faunadb": "^4",
|
||||||
"next": "13.1.1",
|
"next": "13.3.2-canary.12",
|
||||||
"next-auth": "workspace:*",
|
"next-auth": "workspace:*",
|
||||||
"@auth/core": "workspace:*",
|
|
||||||
"nodemailer": "^6",
|
"nodemailer": "^6",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18"
|
"react-dom": "^18"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "1.29.2",
|
||||||
"@types/jsonwebtoken": "^8.5.5",
|
"@types/jsonwebtoken": "^8.5.5",
|
||||||
"@types/react": "^18.0.15",
|
"@types/react": "18.0.37",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
|
"dotenv": "^16.0.3",
|
||||||
"fake-smtp-server": "^0.8.0",
|
"fake-smtp-server": "^0.8.0",
|
||||||
"pg": "^8.7.3",
|
"pg": "^8.7.3",
|
||||||
"prisma": "^3",
|
"prisma": "^3",
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ import { Auth, type AuthConfig } from "@auth/core"
|
|||||||
|
|
||||||
// Providers
|
// Providers
|
||||||
import Apple from "@auth/core/providers/apple"
|
import Apple from "@auth/core/providers/apple"
|
||||||
|
import Asgardeo from "@auth/core/providers/asgardeo"
|
||||||
import Auth0 from "@auth/core/providers/auth0"
|
import Auth0 from "@auth/core/providers/auth0"
|
||||||
import AzureAD from "@auth/core/providers/azure-ad"
|
import AzureAD from "@auth/core/providers/azure-ad"
|
||||||
import AzureB2C from "@auth/core/providers/azure-ad-b2c"
|
import AzureB2C from "@auth/core/providers/azure-ad-b2c"
|
||||||
|
import BeyondIdentity from "@auth/core/providers/beyondidentity"
|
||||||
import BoxyHQSAML from "@auth/core/providers/boxyhq-saml"
|
import BoxyHQSAML from "@auth/core/providers/boxyhq-saml"
|
||||||
// import Cognito from "@auth/core/providers/cognito"
|
// import Cognito from "@auth/core/providers/cognito"
|
||||||
import Credentials from "@auth/core/providers/credentials"
|
import Credentials from "@auth/core/providers/credentials"
|
||||||
@@ -23,6 +25,7 @@ import Instagram from "@auth/core/providers/instagram"
|
|||||||
import Line from "@auth/core/providers/line"
|
import Line from "@auth/core/providers/line"
|
||||||
import LinkedIn from "@auth/core/providers/linkedin"
|
import LinkedIn from "@auth/core/providers/linkedin"
|
||||||
import Mailchimp from "@auth/core/providers/mailchimp"
|
import Mailchimp from "@auth/core/providers/mailchimp"
|
||||||
|
import Notion from "@auth/core/providers/notion"
|
||||||
// import Okta from "@auth/core/providers/okta"
|
// import Okta from "@auth/core/providers/okta"
|
||||||
import Osu from "@auth/core/providers/osu"
|
import Osu from "@auth/core/providers/osu"
|
||||||
import Patreon from "@auth/core/providers/patreon"
|
import Patreon from "@auth/core/providers/patreon"
|
||||||
@@ -31,6 +34,7 @@ import Spotify from "@auth/core/providers/spotify"
|
|||||||
import Trakt from "@auth/core/providers/trakt"
|
import Trakt from "@auth/core/providers/trakt"
|
||||||
import Twitch from "@auth/core/providers/twitch"
|
import Twitch from "@auth/core/providers/twitch"
|
||||||
import Twitter from "@auth/core/providers/twitter"
|
import Twitter from "@auth/core/providers/twitter"
|
||||||
|
import Yandex from "@auth/core/providers/yandex"
|
||||||
import Vk from "@auth/core/providers/vk"
|
import Vk from "@auth/core/providers/vk"
|
||||||
import Wikimedia from "@auth/core/providers/wikimedia"
|
import Wikimedia from "@auth/core/providers/wikimedia"
|
||||||
import WorkOS from "@auth/core/providers/workos"
|
import WorkOS from "@auth/core/providers/workos"
|
||||||
@@ -68,7 +72,7 @@ import WorkOS from "@auth/core/providers/workos"
|
|||||||
|
|
||||||
export const authConfig: AuthConfig = {
|
export const authConfig: AuthConfig = {
|
||||||
// adapter,
|
// adapter,
|
||||||
// debug: process.env.NODE_ENV !== "production",
|
debug: process.env.NODE_ENV !== "production",
|
||||||
theme: {
|
theme: {
|
||||||
logo: "https://next-auth.js.org/img/logo/logo-sm.png",
|
logo: "https://next-auth.js.org/img/logo/logo-sm.png",
|
||||||
brandColor: "#1786fb",
|
brandColor: "#1786fb",
|
||||||
@@ -82,6 +86,7 @@ export const authConfig: AuthConfig = {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Apple({ clientId: process.env.APPLE_ID, clientSecret: process.env.APPLE_SECRET }),
|
Apple({ clientId: process.env.APPLE_ID, clientSecret: process.env.APPLE_SECRET }),
|
||||||
|
Asgardeo({ clientId: process.env.ASGARDEO_CLIENT_ID, clientSecret: process.env.ASGARDEO_CLIENT_SECRET, issuer: process.env.ASGARDEO_ISSUER }),
|
||||||
Auth0({ clientId: process.env.AUTH0_ID, clientSecret: process.env.AUTH0_SECRET, issuer: process.env.AUTH0_ISSUER }),
|
Auth0({ clientId: process.env.AUTH0_ID, clientSecret: process.env.AUTH0_SECRET, issuer: process.env.AUTH0_ISSUER }),
|
||||||
AzureAD({
|
AzureAD({
|
||||||
clientId: process.env.AZURE_AD_CLIENT_ID,
|
clientId: process.env.AZURE_AD_CLIENT_ID,
|
||||||
@@ -89,6 +94,11 @@ export const authConfig: AuthConfig = {
|
|||||||
tenantId: process.env.AZURE_AD_TENANT_ID,
|
tenantId: process.env.AZURE_AD_TENANT_ID,
|
||||||
}),
|
}),
|
||||||
AzureB2C({ clientId: process.env.AZURE_B2C_ID, clientSecret: process.env.AZURE_B2C_SECRET, issuer: process.env.AZURE_B2C_ISSUER }),
|
AzureB2C({ clientId: process.env.AZURE_B2C_ID, clientSecret: process.env.AZURE_B2C_SECRET, issuer: process.env.AZURE_B2C_ISSUER }),
|
||||||
|
BeyondIdentity({
|
||||||
|
clientId: process.env.BEYOND_IDENTITY_CLIENT_ID,
|
||||||
|
clientSecret: process.env.BEYOND_IDENTITY_CLIENT_SECRET,
|
||||||
|
issuer: process.env.BEYOND_IDENTITY_ISSUER,
|
||||||
|
}),
|
||||||
BoxyHQSAML({ issuer: "https://jackson-demo.boxyhq.com", clientId: "tenant=boxyhq.com&product=saml-demo.boxyhq.com", clientSecret: "dummy" }),
|
BoxyHQSAML({ issuer: "https://jackson-demo.boxyhq.com", clientId: "tenant=boxyhq.com&product=saml-demo.boxyhq.com", clientSecret: "dummy" }),
|
||||||
// Cognito({ clientId: process.env.COGNITO_ID, clientSecret: process.env.COGNITO_SECRET, issuer: process.env.COGNITO_ISSUER }),
|
// Cognito({ clientId: process.env.COGNITO_ID, clientSecret: process.env.COGNITO_SECRET, issuer: process.env.COGNITO_ISSUER }),
|
||||||
Discord({ clientId: process.env.DISCORD_ID, clientSecret: process.env.DISCORD_SECRET }),
|
Discord({ clientId: process.env.DISCORD_ID, clientSecret: process.env.DISCORD_SECRET }),
|
||||||
@@ -96,7 +106,7 @@ export const authConfig: AuthConfig = {
|
|||||||
Facebook({ clientId: process.env.FACEBOOK_ID, clientSecret: process.env.FACEBOOK_SECRET }),
|
Facebook({ clientId: process.env.FACEBOOK_ID, clientSecret: process.env.FACEBOOK_SECRET }),
|
||||||
Foursquare({ clientId: process.env.FOURSQUARE_ID, clientSecret: process.env.FOURSQUARE_SECRET }),
|
Foursquare({ clientId: process.env.FOURSQUARE_ID, clientSecret: process.env.FOURSQUARE_SECRET }),
|
||||||
Freshbooks({ clientId: process.env.FRESHBOOKS_ID, clientSecret: process.env.FRESHBOOKS_SECRET }),
|
Freshbooks({ clientId: process.env.FRESHBOOKS_ID, clientSecret: process.env.FRESHBOOKS_SECRET }),
|
||||||
GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET }),
|
GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET, redirectProxy: process.env.AUTH_REDIRECT_PROXY_URL }),
|
||||||
Gitlab({ clientId: process.env.GITLAB_ID, clientSecret: process.env.GITLAB_SECRET }),
|
Gitlab({ clientId: process.env.GITLAB_ID, clientSecret: process.env.GITLAB_SECRET }),
|
||||||
Google({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET }),
|
Google({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET }),
|
||||||
// IDS4({ clientId: process.env.IDS4_ID, clientSecret: process.env.IDS4_SECRET, issuer: process.env.IDS4_ISSUER }),
|
// IDS4({ clientId: process.env.IDS4_ID, clientSecret: process.env.IDS4_SECRET, issuer: process.env.IDS4_ISSUER }),
|
||||||
@@ -105,6 +115,7 @@ export const authConfig: AuthConfig = {
|
|||||||
Line({ clientId: process.env.LINE_ID, clientSecret: process.env.LINE_SECRET }),
|
Line({ clientId: process.env.LINE_ID, clientSecret: process.env.LINE_SECRET }),
|
||||||
LinkedIn({ clientId: process.env.LINKEDIN_ID, clientSecret: process.env.LINKEDIN_SECRET }),
|
LinkedIn({ clientId: process.env.LINKEDIN_ID, clientSecret: process.env.LINKEDIN_SECRET }),
|
||||||
Mailchimp({ clientId: process.env.MAILCHIMP_ID, clientSecret: process.env.MAILCHIMP_SECRET }),
|
Mailchimp({ clientId: process.env.MAILCHIMP_ID, clientSecret: process.env.MAILCHIMP_SECRET }),
|
||||||
|
Notion({ clientId: process.env.NOTION_ID, clientSecret: process.env.NOTION_SECRET, redirectUri: process.env.NOTION_REDIRECT_URI }),
|
||||||
// Okta({ clientId: process.env.OKTA_ID, clientSecret: process.env.OKTA_SECRET, issuer: process.env.OKTA_ISSUER }),
|
// Okta({ clientId: process.env.OKTA_ID, clientSecret: process.env.OKTA_SECRET, issuer: process.env.OKTA_ISSUER }),
|
||||||
Osu({ clientId: process.env.OSU_CLIENT_ID, clientSecret: process.env.OSU_CLIENT_SECRET }),
|
Osu({ clientId: process.env.OSU_CLIENT_ID, clientSecret: process.env.OSU_CLIENT_SECRET }),
|
||||||
Patreon({ clientId: process.env.PATREON_ID, clientSecret: process.env.PATREON_SECRET }),
|
Patreon({ clientId: process.env.PATREON_ID, clientSecret: process.env.PATREON_SECRET }),
|
||||||
@@ -114,6 +125,7 @@ export const authConfig: AuthConfig = {
|
|||||||
Twitch({ clientId: process.env.TWITCH_ID, clientSecret: process.env.TWITCH_SECRET }),
|
Twitch({ clientId: process.env.TWITCH_ID, clientSecret: process.env.TWITCH_SECRET }),
|
||||||
Twitter({ clientId: process.env.TWITTER_ID, clientSecret: process.env.TWITTER_SECRET }),
|
Twitter({ clientId: process.env.TWITTER_ID, clientSecret: process.env.TWITTER_SECRET }),
|
||||||
// TwitterLegacy({ clientId: process.env.TWITTER_LEGACY_ID, clientSecret: process.env.TWITTER_LEGACY_SECRET }),
|
// TwitterLegacy({ clientId: process.env.TWITTER_LEGACY_ID, clientSecret: process.env.TWITTER_LEGACY_SECRET }),
|
||||||
|
Yandex({ clientId: process.env.YANDEX_ID, clientSecret: process.env.YANDEX_SECRET }),
|
||||||
Vk({ clientId: process.env.VK_ID, clientSecret: process.env.VK_SECRET }),
|
Vk({ clientId: process.env.VK_ID, clientSecret: process.env.VK_SECRET }),
|
||||||
Wikimedia({ clientId: process.env.WIKIMEDIA_ID, clientSecret: process.env.WIKIMEDIA_SECRET }),
|
Wikimedia({ clientId: process.env.WIKIMEDIA_ID, clientSecret: process.env.WIKIMEDIA_SECRET }),
|
||||||
WorkOS({ clientId: process.env.WORKOS_ID, clientSecret: process.env.WORKOS_SECRET }),
|
WorkOS({ clientId: process.env.WORKOS_ID, clientSecret: process.env.WORKOS_SECRET }),
|
||||||
@@ -148,4 +160,4 @@ function AuthHandler(...args: any[]) {
|
|||||||
|
|
||||||
export default AuthHandler(authConfig)
|
export default AuthHandler(authConfig)
|
||||||
|
|
||||||
export const config = { runtime: "experimental-edge" }
|
export const config = { runtime: "edge" }
|
||||||
19
apps/dev/nextjs/pages/api/examples/protected.ts
Normal file
19
apps/dev/nextjs/pages/api/examples/protected.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// This is an example of to protect an API route
|
||||||
|
import { authConfig } from "../auth-old/[...nextauth]"
|
||||||
|
import { getServerSession } from "next-auth/next"
|
||||||
|
|
||||||
|
export default async (req, res) => {
|
||||||
|
const session = await getServerSession(req, res, authConfig as any)
|
||||||
|
|
||||||
|
if (session) {
|
||||||
|
res.send({
|
||||||
|
content:
|
||||||
|
"This is protected content. You can access this content because you are signed in.",
|
||||||
|
session,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
res.send({
|
||||||
|
error: "You must be sign in to view the protected content on this page.",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
8
apps/dev/nextjs/pages/api/examples/session.ts
Normal file
8
apps/dev/nextjs/pages/api/examples/session.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { authConfig } from "../auth-old/[...nextauth]"
|
||||||
|
// This is an example of how to access a session from an API route
|
||||||
|
import { getServerSession } from "next-auth/next"
|
||||||
|
|
||||||
|
export default async (req, res) => {
|
||||||
|
const session = await getServerSession(req, res, authConfig as any)
|
||||||
|
res.json(session)
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// This is an example of how to protect content using server rendering
|
// This is an example of how to protect content using server rendering
|
||||||
import { unstable_getServerSession } from "next-auth/next"
|
import { getServerSession } from "next-auth/next"
|
||||||
import { authOptions } from "./api/auth/[...nextauth]"
|
import { authConfig } from "./api/auth-old/[...nextauth]"
|
||||||
import Layout from "../components/layout"
|
import Layout from "../components/layout"
|
||||||
import AccessDenied from "../components/access-denied"
|
import AccessDenied from "../components/access-denied"
|
||||||
|
|
||||||
@@ -26,11 +26,7 @@ export default function Page({ content, session }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getServerSideProps(context) {
|
export async function getServerSideProps(context) {
|
||||||
const session = await unstable_getServerSession(
|
const session = await getServerSession(context.req, context.res, authConfig)
|
||||||
context.req,
|
|
||||||
context.res,
|
|
||||||
authOptions
|
|
||||||
)
|
|
||||||
let content = null
|
let content = null
|
||||||
|
|
||||||
if (session) {
|
if (session) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { unstable_getServerSession } from "next-auth/next"
|
import { getServerSession } from "next-auth/next"
|
||||||
import Layout from "../components/layout"
|
import Layout from "../components/layout"
|
||||||
import { authOptions } from "./api/auth/[...nextauth]"
|
import { authConfig } from "./api/auth-old/[...nextauth]"
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
// As this page uses Server Side Rendering, the `session` will be already
|
// As this page uses Server Side Rendering, the `session` will be already
|
||||||
@@ -12,11 +12,11 @@ export default function Page() {
|
|||||||
<Layout>
|
<Layout>
|
||||||
<h1>Server Side Rendering</h1>
|
<h1>Server Side Rendering</h1>
|
||||||
<p>
|
<p>
|
||||||
This page uses the <strong>unstable_getServerSession()</strong> method
|
This page uses the <strong>getServerSession()</strong> method in{" "}
|
||||||
in <strong>getServerSideProps()</strong>.
|
<strong>getServerSideProps()</strong>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Using <strong>unstable_getServerSession()</strong> in{" "}
|
Using <strong>getServerSession()</strong> in{" "}
|
||||||
<strong>getServerSideProps()</strong> is currently the recommended
|
<strong>getServerSideProps()</strong> is currently the recommended
|
||||||
approach, although the API may still change, if you need to support
|
approach, although the API may still change, if you need to support
|
||||||
Server Side Rendering with authentication.
|
Server Side Rendering with authentication.
|
||||||
@@ -40,11 +40,7 @@ export default function Page() {
|
|||||||
export async function getServerSideProps(context) {
|
export async function getServerSideProps(context) {
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
session: await unstable_getServerSession(
|
session: await getServerSession(context.req, context.res, authConfig),
|
||||||
context.req,
|
|
||||||
context.res,
|
|
||||||
authOptions
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
107
apps/dev/nextjs/playwright.config.ts
Normal file
107
apps/dev/nextjs/playwright.config.ts
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import type { PlaywrightTestConfig } from '@playwright/test';
|
||||||
|
import { devices } from '@playwright/test';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read environment variables from file.
|
||||||
|
* https://github.com/motdotla/dotenv
|
||||||
|
*/
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
|
*/
|
||||||
|
const config: PlaywrightTestConfig = {
|
||||||
|
testDir: './tests',
|
||||||
|
/* Maximum time one test can run for. */
|
||||||
|
timeout: 30 * 1000,
|
||||||
|
expect: {
|
||||||
|
/**
|
||||||
|
* Maximum time expect() should wait for the condition to be met.
|
||||||
|
* For example in `await expect(locator).toHaveText();`
|
||||||
|
*/
|
||||||
|
timeout: 5000
|
||||||
|
},
|
||||||
|
/* Run tests in files in parallel */
|
||||||
|
fullyParallel: true,
|
||||||
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
/* Retry on CI only */
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
/* Opt out of parallel tests on CI. */
|
||||||
|
workers: process.env.CI ? 1 : undefined,
|
||||||
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
|
reporter: 'html',
|
||||||
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
use: {
|
||||||
|
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
|
||||||
|
actionTimeout: 0,
|
||||||
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
|
// baseURL: 'http://localhost:3000',
|
||||||
|
|
||||||
|
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||||
|
trace: 'on-first-retry',
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Configure projects for major browsers */
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
use: {
|
||||||
|
...devices['Desktop Chrome'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'firefox',
|
||||||
|
use: {
|
||||||
|
...devices['Desktop Firefox'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'webkit',
|
||||||
|
use: {
|
||||||
|
...devices['Desktop Safari'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Test against mobile viewports. */
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Chrome',
|
||||||
|
// use: {
|
||||||
|
// ...devices['Pixel 5'],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Safari',
|
||||||
|
// use: {
|
||||||
|
// ...devices['iPhone 12'],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
|
||||||
|
/* Test against branded browsers. */
|
||||||
|
// {
|
||||||
|
// name: 'Microsoft Edge',
|
||||||
|
// use: {
|
||||||
|
// channel: 'msedge',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Google Chrome',
|
||||||
|
// use: {
|
||||||
|
// channel: 'chrome',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
|
||||||
|
/* Folder for test artifacts such as screenshots, videos, traces, etc. */
|
||||||
|
// outputDir: 'test-results/',
|
||||||
|
|
||||||
|
/* Run your local dev server before starting the tests */
|
||||||
|
// webServer: {
|
||||||
|
// command: 'npm run start',
|
||||||
|
// port: 3000,
|
||||||
|
// },
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
39
apps/dev/nextjs/tests/signin.spec.ts
Normal file
39
apps/dev/nextjs/tests/signin.spec.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { test, expect } from "@playwright/test"
|
||||||
|
|
||||||
|
test("Sign in with Auth0", async ({ page }) => {
|
||||||
|
// Go to NextAuth example app
|
||||||
|
await page.goto("https://next-auth-example.vercel.app")
|
||||||
|
|
||||||
|
// Click 'Sign In'
|
||||||
|
await page.click("#__next > header > div > p > a")
|
||||||
|
|
||||||
|
// Auth0 Login Provider
|
||||||
|
await page.click('body > div > div form[action*="auth0"] > button')
|
||||||
|
|
||||||
|
// Enter Credentials (Username/Password Login) on Auth0 Widget
|
||||||
|
await page.type("#username", process.env.AUTH0_USERNAME!)
|
||||||
|
await page.type("#password", process.env.AUTH0_PASSWORD!)
|
||||||
|
|
||||||
|
// Snap a screenshot
|
||||||
|
// await page.screenshot({ path: "1-auth0-login.png", fullPage: true })
|
||||||
|
|
||||||
|
// Press submit on Auth0 form
|
||||||
|
await page.click('body > div > main > section > div button[type="submit"]')
|
||||||
|
|
||||||
|
// Wait for next-auth example page login status header to appear
|
||||||
|
await page.waitForTimeout(2000)
|
||||||
|
|
||||||
|
// Snap a screenshot
|
||||||
|
// await page.screenshot({
|
||||||
|
// path: "2-next-auth-redirect-result.png",
|
||||||
|
// fullPage: false,
|
||||||
|
// })
|
||||||
|
|
||||||
|
// Check session object after successful login
|
||||||
|
const response = await page.goto(
|
||||||
|
"https://next-auth-example.vercel.app/api/auth/session"
|
||||||
|
)
|
||||||
|
const session = await response?.json()
|
||||||
|
expect(session?.user?.email).toBe(process.env.AUTH0_USERNAME)
|
||||||
|
// TODO: Check whole object with .toEqual()
|
||||||
|
})
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": false,
|
"strict": false,
|
||||||
@@ -19,8 +23,17 @@
|
|||||||
{
|
{
|
||||||
"name": "next"
|
"name": "next"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"strictNullChecks": true
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
"include": [
|
||||||
"exclude": ["node_modules", "jest.config.js"]
|
"next-env.d.ts",
|
||||||
}
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".next/types/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"jest.config.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
9
apps/dev/nextjs/types/nextauth.d.ts
vendored
9
apps/dev/nextjs/types/nextauth.d.ts
vendored
@@ -18,3 +18,12 @@ declare module "next-auth" {
|
|||||||
foo: string
|
foo: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace NodeJS {
|
||||||
|
interface ProcessEnv {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,8 +19,8 @@
|
|||||||
"vite": "4.0.1"
|
"vite": "4.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth/core": "latest",
|
"@auth/core": "workspace:*",
|
||||||
"@auth/sveltekit": "latest"
|
"@auth/sveltekit": "workspace:*"
|
||||||
},
|
},
|
||||||
"type": "module"
|
"type": "module"
|
||||||
}
|
}
|
||||||
|
|||||||
4
apps/examples/next.config.js
Normal file
4
apps/examples/next.config.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/** @type {import("next").NextConfig} */
|
||||||
|
module.exports = {
|
||||||
|
reactStrictMode: true,
|
||||||
|
}
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
NEXTAUTH_URL=http://localhost:3000
|
NEXTAUTH_URL=http://localhost:3000
|
||||||
NEXTAUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32
|
NEXTAUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.vercel.app/32
|
||||||
|
|
||||||
APPLE_ID=
|
|
||||||
APPLE_TEAM_ID=
|
|
||||||
APPLE_PRIVATE_KEY=
|
|
||||||
APPLE_KEY_ID=
|
|
||||||
|
|
||||||
AUTH0_ID=
|
AUTH0_ID=
|
||||||
AUTH0_SECRET=
|
AUTH0_SECRET=
|
||||||
@@ -21,8 +17,3 @@ GOOGLE_SECRET=
|
|||||||
|
|
||||||
TWITTER_ID=
|
TWITTER_ID=
|
||||||
TWITTER_SECRET=
|
TWITTER_SECRET=
|
||||||
|
|
||||||
EMAIL_SERVER=smtp://username:password@smtp.example.com:587
|
|
||||||
EMAIL_FROM=NextAuth <noreply@example.com>
|
|
||||||
|
|
||||||
DATABASE_URL=sqlite://localhost/:memory:?synchronize=true
|
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
> The example repository is maintained from a [monorepo](https://github.com/nextauthjs/next-auth/tree/main/apps/example-nextjs). Pull Requests should be opened against [`nextauthjs/next-auth`](https://github.com/nextauthjs/next-auth).
|
> The example repository is maintained from a [monorepo](https://github.com/nextauthjs/next-auth/tree/main/apps/examples/nextjs). Pull Requests should be opened against [`nextauthjs/next-auth`](https://github.com/nextauthjs/next-auth).
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://next-auth.js.org" target="_blank"><img width="150px" src="https://next-auth.js.org/img/logo/logo-sm.png" /></a>
|
<a href="https://authjs.dev" target="_blank">
|
||||||
<h3 align="center">NextAuth.js Example App</h3>
|
<img height="64" src="https://authjs.dev/img/logo/logo-sm.png" />
|
||||||
|
</a>
|
||||||
|
<a href="https://nextjs.org" target="_blank">
|
||||||
|
<img height="64" src="https://nextjs.org/static/favicon/android-chrome-192x192.png" />
|
||||||
|
</a>
|
||||||
|
<h3 align="center"><b>next-auth</b> - Example App</h3>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Open Source. Full Stack. Own Your Data.
|
Open Source. Full Stack. Own Your Data.
|
||||||
</p>
|
</p>
|
||||||
@@ -25,19 +30,13 @@
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
NextAuth.js is a complete open source authentication solution.
|
NextAuth.js is a complete open-source authentication solution.
|
||||||
|
|
||||||
This is an example application that shows how `next-auth` is applied to a basic Next.js app.
|
This is an example application that shows how `next-auth` is applied to a basic Next.js app.
|
||||||
|
|
||||||
The deployed version can be found at [`next-auth-example.vercel.app`](https://next-auth-example.vercel.app)
|
The deployed version can be found at [`next-auth-example.vercel.app`](https://next-auth-example.vercel.app)
|
||||||
|
|
||||||
### About NextAuth.js
|
Go to [authjs.dev](https://authjs.dev) for more information and documentation.
|
||||||
|
|
||||||
NextAuth.js is an easy to implement, full-stack (client/server) open source authentication library originally designed for [Next.js](https://nextjs.org) and [Serverless](https://vercel.com). Our goal is to [support even more frameworks](https://github.com/nextauthjs/next-auth/issues/2294) in the future.
|
|
||||||
|
|
||||||
Go to [next-auth.js.org](https://next-auth.js.org) for more information and documentation.
|
|
||||||
|
|
||||||
> _NextAuth.js is not officially associated with Vercel or Next.js._
|
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
@@ -67,7 +66,7 @@ You **can** skip configuring a database and come back to it later if you want.
|
|||||||
|
|
||||||
For more information about setting up a database, please check out the following links:
|
For more information about setting up a database, please check out the following links:
|
||||||
|
|
||||||
- Docs: [next-auth.js.org/adapters/overview](https://next-auth.js.org/adapters/overview)
|
- Docs: [authjs.dev/reference/adapters](https://authjs.dev/reference/adapters)
|
||||||
|
|
||||||
### 3. Configure Authentication Providers
|
### 3. Configure Authentication Providers
|
||||||
|
|
||||||
@@ -77,7 +76,7 @@ For more information about setting up a database, please check out the following
|
|||||||
|
|
||||||
e.g. For Google OAuth you would use: `http://localhost:3000/api/auth/callback/google`
|
e.g. For Google OAuth you would use: `http://localhost:3000/api/auth/callback/google`
|
||||||
|
|
||||||
A list of configured providers and their callback URLs is available from the endpoint `/api/auth/providers`. You can find more information at https://next-auth.js.org/configuration/providers/oauth
|
A list of configured providers and their callback URLs is available from the endpoint `/api/auth/providers`. You can find more information at [authjs.dev/getting-started/oauth-tutorial](https://authjs.dev/getting-started/oauth-tutorial)
|
||||||
|
|
||||||
3. You can also choose to specify an SMTP server for passwordless sign in via email.
|
3. You can also choose to specify an SMTP server for passwordless sign in via email.
|
||||||
|
|
||||||
@@ -98,15 +97,13 @@ npm run start
|
|||||||
|
|
||||||
### 5. Preparing for Production
|
### 5. Preparing for Production
|
||||||
|
|
||||||
Follow the [Deployment documentation](https://next-auth.js.org/deployment)
|
Follow the [Deployment documentation](https://authjs.dev/guides/basics/deployment) or deploy the example instantly using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-auth-example)
|
||||||
|
|
||||||
|
[](https://vercel.com/new/git/external?repository-url=https://github.com/nextauthjs/next-auth-example&project-name=next-auth-example&repository-name=next-auth-example)
|
||||||
|
|
||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
|
||||||
<a href="https://vercel.com?utm_source=nextauthjs&utm_campaign=oss">
|
<a href="https://vercel.com?utm_source=nextauthjs&utm_campaign=oss">
|
||||||
<img width="170px" src="https://raw.githubusercontent.com/nextauthjs/next-auth/canary/www/static/img/powered-by-vercel.svg" alt="Powered By Vercel" />
|
<img width="170px" src="https://raw.githubusercontent.com/nextauthjs/next-auth/main/docs/static/img/powered-by-vercel.svg" alt="Powered By Vercel" />
|
||||||
</a>
|
</a>
|
||||||
<p align="left">Thanks to Vercel sponsoring this project by allowing it to be deployed for free for the entire NextAuth.js Team</p>
|
<p align="left">Thanks to Vercel sponsoring this project by allowing it to be deployed for free for the entire Auth.js Team</p>
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
ISC
|
|
||||||
|
|||||||
3
apps/examples/nextjs/app/api/auth/[...nextauth]/route.ts
Normal file
3
apps/examples/nextjs/app/api/auth/[...nextauth]/route.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { handlers } from "auth"
|
||||||
|
export const { GET, POST } = handlers
|
||||||
|
export const runtime = "edge"
|
||||||
10
apps/examples/nextjs/app/api/protected/route.ts
Normal file
10
apps/examples/nextjs/app/api/protected/route.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { auth } from "auth"
|
||||||
|
import { NextResponse } from "next/server"
|
||||||
|
|
||||||
|
export const GET = auth(function GET(req) {
|
||||||
|
if (req.auth) {
|
||||||
|
return NextResponse.json(req.auth)
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json({ message: "Not authenticated" }, { status: 401 })
|
||||||
|
})
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
import Layout from "../components/layout"
|
export default function Page() {
|
||||||
|
|
||||||
export default function ClientPage() {
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<>
|
||||||
<h1>Client Side Rendering</h1>
|
<h1>Client Side Rendering</h1>
|
||||||
<p>
|
<p>
|
||||||
This page uses the <strong>useSession()</strong> React Hook in the{" "}
|
This page uses the <strong>useSession()</strong> React Hook in the{" "}
|
||||||
<strong><Header/></strong> component.
|
<strong></Header></strong> component.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The <strong>useSession()</strong> React Hook is easy to use and allows
|
The <strong>useSession()</strong> React Hook easy to use and allows
|
||||||
pages to render very quickly.
|
pages to render very quickly.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
@@ -22,6 +20,6 @@ export default function ClientPage() {
|
|||||||
The disadvantage of <strong>useSession()</strong> is that it requires
|
The disadvantage of <strong>useSession()</strong> is that it requires
|
||||||
client side JavaScript.
|
client side JavaScript.
|
||||||
</p>
|
</p>
|
||||||
</Layout>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
24
apps/examples/nextjs/app/layout.tsx
Normal file
24
apps/examples/nextjs/app/layout.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import Header from "components/header"
|
||||||
|
import Footer from "components/footer"
|
||||||
|
import './styles.css'
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<html>
|
||||||
|
<head></head>
|
||||||
|
<body>
|
||||||
|
<Header />
|
||||||
|
<main>
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const runtime = "experimental-edge"
|
||||||
13
apps/examples/nextjs/app/page.tsx
Normal file
13
apps/examples/nextjs/app/page.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>NextAuth.js Example</h1>
|
||||||
|
<p>
|
||||||
|
This is an example site to demonstrate how to use{" "}
|
||||||
|
<a href="https://authjs.dev">NextAuth.js</a> for authentication.
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const runtime = "experimental-edge"
|
||||||
39
apps/examples/nextjs/app/server-component/page.tsx
Normal file
39
apps/examples/nextjs/app/server-component/page.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { auth } from "auth"
|
||||||
|
import { cookies, headers } from "next/headers"
|
||||||
|
|
||||||
|
function SignIn({ id, children, className }: any) {
|
||||||
|
const $cookies = cookies()
|
||||||
|
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||||
|
return (
|
||||||
|
<form action={`/api/auth/signin/${id}`} method="post">
|
||||||
|
<button className={className} type="submit">{children}</button>
|
||||||
|
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SignOut({ children }: any) {
|
||||||
|
const $cookies = cookies()
|
||||||
|
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||||
|
return (
|
||||||
|
<form action="/api/auth/signout" method="post">
|
||||||
|
<button type="submit">{children}</button>
|
||||||
|
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
const session = await auth(headers())
|
||||||
|
if (session) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<pre>{JSON.stringify(session, null, 2)}</pre>
|
||||||
|
<SignOut>Sign out</SignOut>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return <SignIn id="github">Sign in with github</SignIn>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const runtime = "experimental-edge"
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
body {
|
body {
|
||||||
|
color: red;
|
||||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
||||||
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
|
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
|
||||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
@@ -6,7 +7,7 @@ body {
|
|||||||
max-width: 680px;
|
max-width: 680px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
color: #333;
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
li,
|
li,
|
||||||
21
apps/examples/nextjs/auth.ts
Normal file
21
apps/examples/nextjs/auth.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import NextAuth from "next-auth"
|
||||||
|
import GitHub from "@auth/core/providers/github"
|
||||||
|
|
||||||
|
export const { handlers, auth } = NextAuth({
|
||||||
|
providers: [GitHub],
|
||||||
|
callbacks: {
|
||||||
|
async authorized({ request, auth }) {
|
||||||
|
// if (request.method === "POST") {
|
||||||
|
// const [, token] = request.headers.get("Authorization")?.split(" ")
|
||||||
|
// const valid = validateToken(token)
|
||||||
|
// // If the request has a valid auth token, it is authorized
|
||||||
|
// if (valid) return true
|
||||||
|
// return NextResponse.json("Invalid auth token", { status: 401 })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Logged in users are authorized, otherwise, will redirect to login
|
||||||
|
// You could also return a custom redirect instead of the sign-in page
|
||||||
|
return !!auth
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import styles from "./footer.module.css"
|
import styles from "./footer.module.css"
|
||||||
import packageJSON from "../package.json"
|
import packageJSON from "next-auth/package.json"
|
||||||
|
|
||||||
export default function Footer() {
|
export default function Footer() {
|
||||||
return (
|
return (
|
||||||
@@ -8,10 +8,10 @@ export default function Footer() {
|
|||||||
<hr />
|
<hr />
|
||||||
<ul className={styles.navItems}>
|
<ul className={styles.navItems}>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<a href="https://next-auth.js.org">Documentation</a>
|
<a href="https://authjs.dev">Documentation</a>
|
||||||
</li>
|
</li>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<a href="https://www.npmjs.com/package/next-auth">NPM</a>
|
<a href="https://www.npmjs.com/package/@auth/core">NPM</a>
|
||||||
</li>
|
</li>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<a href="https://github.com/nextauthjs/next-auth-example">GitHub</a>
|
<a href="https://github.com/nextauthjs/next-auth-example">GitHub</a>
|
||||||
@@ -20,7 +20,7 @@ export default function Footer() {
|
|||||||
<Link href="/policy">Policy</Link>
|
<Link href="/policy">Policy</Link>
|
||||||
</li>
|
</li>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<em>next-auth@{packageJSON.dependencies["next-auth"]}</em>
|
<em>{packageJSON.version}</em>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/* Set min-height to avoid page reflow while session loading */
|
/* Set min-height to avoid page reflow while session loading */
|
||||||
.signedInStatus {
|
.signedInStatus {
|
||||||
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
min-height: 4rem;
|
min-height: 4rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -1,65 +1,63 @@
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { signIn, signOut, useSession } from "next-auth/react"
|
import { auth } from "auth"
|
||||||
|
import { cookies, headers } from "next/headers"
|
||||||
import styles from "./header.module.css"
|
import styles from "./header.module.css"
|
||||||
|
|
||||||
// The approach used in this component shows how to build a sign in and sign out
|
function SignIn({ id, children, className }: any) {
|
||||||
|
const $cookies = cookies()
|
||||||
|
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||||
|
return (
|
||||||
|
<form action={`/api/auth/signin/${id}`} method="post">
|
||||||
|
<button className={className} type="submit">{children}</button>
|
||||||
|
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SignOut({ children, className }: any) {
|
||||||
|
const $cookies = cookies()
|
||||||
|
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||||
|
return (
|
||||||
|
<form action="/api/auth/signout" method="post">
|
||||||
|
<button className={className} type="submit">{children}</button>
|
||||||
|
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The approach used in this component shows how to built a sign in and sign out
|
||||||
// component that works on pages which support both client and server side
|
// component that works on pages which support both client and server side
|
||||||
// rendering, and avoids any flash incorrect content on initial page load.
|
// rendering, and avoids any flash incorrect content on initial page load.
|
||||||
export default function Header() {
|
export default async function Header() {
|
||||||
const { data: session, status } = useSession()
|
const session = await auth(headers())
|
||||||
const loading = status === "loading"
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header>
|
<header>
|
||||||
<noscript>
|
<noscript>
|
||||||
<style>{`.nojs-show { opacity: 1; top: 0; }`}</style>
|
<style>{".nojs-show { opacity: 1; top: 0; }"}</style>
|
||||||
</noscript>
|
</noscript>
|
||||||
<div className={styles.signedInStatus}>
|
<div className={styles.signedInStatus}>
|
||||||
<p
|
<p className={`nojs-show ${styles.loaded}`}>
|
||||||
className={`nojs-show ${
|
|
||||||
!session && loading ? styles.loading : styles.loaded
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{!session && (
|
{!session && (
|
||||||
<>
|
<>
|
||||||
<span className={styles.notSignedInText}>
|
<span className={styles.notSignedInText}>
|
||||||
You are not signed in
|
You are not signed in
|
||||||
</span>
|
</span>
|
||||||
<a
|
<SignIn className={styles.buttonPrimary}>Sign In</SignIn>
|
||||||
href={`/api/auth/signin`}
|
|
||||||
className={styles.buttonPrimary}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault()
|
|
||||||
signIn()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Sign in
|
|
||||||
</a>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{session?.user && (
|
{session && (
|
||||||
<>
|
<>
|
||||||
{session.user.image && (
|
{session.user.image && (
|
||||||
<span
|
<img src={session.user.image} className={styles.avatar} />
|
||||||
style={{ backgroundImage: `url('${session.user.image}')` }}
|
|
||||||
className={styles.avatar}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
<span className={styles.signedInText}>
|
<span className={styles.signedInText}>
|
||||||
<small>Signed in as</small>
|
<small>Signed in as</small>
|
||||||
<br />
|
<br />
|
||||||
<strong>{session.user.email ?? session.user.name}</strong>
|
<strong>{session.user.email} </strong>
|
||||||
|
{session.user.name ? `(${session.user.name})` : null}
|
||||||
</span>
|
</span>
|
||||||
<a
|
<SignOut className={styles.button}>Sign Out</SignOut>
|
||||||
href={`/api/auth/signout`}
|
|
||||||
className={styles.button}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault()
|
|
||||||
signOut()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Sign out
|
|
||||||
</a>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
@@ -73,7 +71,7 @@ export default function Header() {
|
|||||||
<Link href="/client">Client</Link>
|
<Link href="/client">Client</Link>
|
||||||
</li>
|
</li>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<Link href="/server">Server</Link>
|
<Link href="/server-component">Server</Link>
|
||||||
</li>
|
</li>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<Link href="/protected">Protected</Link>
|
<Link href="/protected">Protected</Link>
|
||||||
@@ -82,13 +80,12 @@ export default function Header() {
|
|||||||
<Link href="/api-example">API</Link>
|
<Link href="/api-example">API</Link>
|
||||||
</li>
|
</li>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<Link href="/admin">Admin</Link>
|
<Link href="/middleware-protected">Middleware protected</Link>
|
||||||
</li>
|
|
||||||
<li className={styles.navItem}>
|
|
||||||
<Link href="/me">Me</Link>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const runtime = "experimental-edge"
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import Header from "./header"
|
|
||||||
import Footer from "./footer"
|
|
||||||
import type { ReactNode } from "react"
|
|
||||||
|
|
||||||
export default function Layout({ children }: { children: ReactNode }) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Header />
|
|
||||||
<main>{children}</main>
|
|
||||||
<Footer />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,17 +1,10 @@
|
|||||||
import { withAuth } from "next-auth/middleware"
|
// export { auth as default } from "auth"
|
||||||
|
import { auth } from "auth"
|
||||||
|
import { NextResponse } from "next/server"
|
||||||
|
|
||||||
// More on how NextAuth.js middleware works: https://next-auth.js.org/configuration/nextjs#middleware
|
export default auth((req) => {
|
||||||
export default withAuth({
|
if (req.auth) return NextResponse.json(req.auth)
|
||||||
callbacks: {
|
return NextResponse.json("Not authorized", { status: 401 })
|
||||||
authorized({ req, token }) {
|
|
||||||
// `/admin` requires admin role
|
|
||||||
if (req.nextUrl.pathname === "/admin") {
|
|
||||||
return token?.userRole === "admin"
|
|
||||||
}
|
|
||||||
// `/me` only requires the user to be logged in
|
|
||||||
return !!token
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const config = { matcher: ["/admin", "/me"] }
|
export const config = { matcher: ["/middleware-protected"] }
|
||||||
|
|||||||
10
apps/examples/nextjs/next-auth.d.ts
vendored
10
apps/examples/nextjs/next-auth.d.ts
vendored
@@ -1,10 +0,0 @@
|
|||||||
import "next-auth/jwt"
|
|
||||||
|
|
||||||
// Read more at: https://next-auth.js.org/getting-started/typescript#module-augmentation
|
|
||||||
|
|
||||||
declare module "next-auth/jwt" {
|
|
||||||
interface JWT {
|
|
||||||
/** The user's role. */
|
|
||||||
userRole?: "admin"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
9
apps/examples/nextjs/next.config.js
Normal file
9
apps/examples/nextjs/next.config.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/** @type {import("next").NextConfig} */
|
||||||
|
module.exports = {
|
||||||
|
webpack(config) {
|
||||||
|
config.experiments = { ...config.experiments, topLevelAwait: true }
|
||||||
|
return config
|
||||||
|
},
|
||||||
|
experimental: { appDir: true },
|
||||||
|
typescript: { ignoreBuildErrors: true },
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"name": "nextjs-example-app",
|
||||||
"description": "An example project for NextAuth.js with Next.js",
|
"description": "An example project for NextAuth.js with Next.js",
|
||||||
"repository": "https://github.com/nextauthjs/next-auth-example.git",
|
"repository": "https://github.com/nextauthjs/next-auth-example.git",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
@@ -18,15 +19,15 @@
|
|||||||
"Lluis Agusti <hi@llu.lu>"
|
"Lluis Agusti <hi@llu.lu>"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@auth/core": "workspace:*",
|
||||||
"next": "latest",
|
"next": "latest",
|
||||||
"next-auth": "latest",
|
"next-auth": "workspace:*",
|
||||||
"nodemailer": "^6",
|
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^17",
|
"@types/node": "^18.16.2",
|
||||||
"@types/react": "^18.0.15",
|
"@types/react": "^18.2.0",
|
||||||
"typescript": "^4"
|
"typescript": "^5.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
import { SessionProvider } from "next-auth/react"
|
|
||||||
import "./styles.css"
|
|
||||||
|
|
||||||
import type { AppProps } from "next/app"
|
|
||||||
import type { Session } from "next-auth"
|
|
||||||
|
|
||||||
// Use of the <SessionProvider> is mandatory to allow components that call
|
|
||||||
// `useSession()` anywhere in your application to access the `session` object.
|
|
||||||
export default function App({
|
|
||||||
Component,
|
|
||||||
pageProps: { session, ...pageProps },
|
|
||||||
}: AppProps<{ session: Session }>) {
|
|
||||||
return (
|
|
||||||
<SessionProvider session={session}>
|
|
||||||
<Component {...pageProps} />
|
|
||||||
</SessionProvider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import Layout from "../components/layout"
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
return (
|
|
||||||
<Layout>
|
|
||||||
<h1>This page is protected by Middleware</h1>
|
|
||||||
<p>Only admin users can see this page.</p>
|
|
||||||
<p>
|
|
||||||
To learn more about the NextAuth middleware see
|
|
||||||
<a href="https://docs-git-misc-docs-nextauthjs.vercel.app/configuration/nextjs#middleware">
|
|
||||||
the docs
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</p>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
import NextAuth, { NextAuthOptions } from "next-auth"
|
|
||||||
import GoogleProvider from "next-auth/providers/google"
|
|
||||||
import FacebookProvider from "next-auth/providers/facebook"
|
|
||||||
import GithubProvider from "next-auth/providers/github"
|
|
||||||
import TwitterProvider from "next-auth/providers/twitter"
|
|
||||||
import Auth0Provider from "next-auth/providers/auth0"
|
|
||||||
// import AppleProvider from "next-auth/providers/apple"
|
|
||||||
// import EmailProvider from "next-auth/providers/email"
|
|
||||||
|
|
||||||
// For more information on each option (and a full list of options) go to
|
|
||||||
// https://next-auth.js.org/configuration/options
|
|
||||||
export const authOptions: NextAuthOptions = {
|
|
||||||
// https://next-auth.js.org/configuration/providers/oauth
|
|
||||||
providers: [
|
|
||||||
/* EmailProvider({
|
|
||||||
server: process.env.EMAIL_SERVER,
|
|
||||||
from: process.env.EMAIL_FROM,
|
|
||||||
}),
|
|
||||||
// Temporarily removing the Apple provider from the demo site as the
|
|
||||||
// callback URL for it needs updating due to Vercel changing domains
|
|
||||||
|
|
||||||
Providers.Apple({
|
|
||||||
clientId: process.env.APPLE_ID,
|
|
||||||
clientSecret: {
|
|
||||||
appleId: process.env.APPLE_ID,
|
|
||||||
teamId: process.env.APPLE_TEAM_ID,
|
|
||||||
privateKey: process.env.APPLE_PRIVATE_KEY,
|
|
||||||
keyId: process.env.APPLE_KEY_ID,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
*/
|
|
||||||
FacebookProvider({
|
|
||||||
clientId: process.env.FACEBOOK_ID,
|
|
||||||
clientSecret: process.env.FACEBOOK_SECRET,
|
|
||||||
}),
|
|
||||||
GithubProvider({
|
|
||||||
clientId: process.env.GITHUB_ID,
|
|
||||||
clientSecret: process.env.GITHUB_SECRET,
|
|
||||||
}),
|
|
||||||
GoogleProvider({
|
|
||||||
clientId: process.env.GOOGLE_ID,
|
|
||||||
clientSecret: process.env.GOOGLE_SECRET,
|
|
||||||
}),
|
|
||||||
TwitterProvider({
|
|
||||||
clientId: process.env.TWITTER_ID,
|
|
||||||
clientSecret: process.env.TWITTER_SECRET,
|
|
||||||
}),
|
|
||||||
Auth0Provider({
|
|
||||||
clientId: process.env.AUTH0_ID,
|
|
||||||
clientSecret: process.env.AUTH0_SECRET,
|
|
||||||
issuer: process.env.AUTH0_ISSUER,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
theme: {
|
|
||||||
colorScheme: "light",
|
|
||||||
},
|
|
||||||
callbacks: {
|
|
||||||
async jwt({ token }) {
|
|
||||||
token.userRole = "admin"
|
|
||||||
return token
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default NextAuth(authOptions)
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user