mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
3 Commits
@auth/core
...
fix/callba
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
079fbd27fa | ||
|
|
c7101981bc | ||
|
|
f7b052a5fd |
70
.eslintignore
Normal file
70
.eslintignore
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
.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
Normal file
75
.eslintrc.js
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
// @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,@auth/*"
|
npx envinfo --system --binaries --browsers --npmPackages "next,react,next-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:
|
||||||
|
|||||||
6
.github/ISSUE_TEMPLATE/2_bug_provider.yml
vendored
6
.github/ISSUE_TEMPLATE/2_bug_provider.yml
vendored
@@ -25,19 +25,16 @@ 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"
|
||||||
- "Coinbase"
|
- "Coinbase"
|
||||||
- "Descope"
|
|
||||||
- "Discord"
|
- "Discord"
|
||||||
- "Dropbox"
|
- "Dropbox"
|
||||||
- "EVE Online"
|
- "EVE Online"
|
||||||
@@ -60,7 +57,6 @@ body:
|
|||||||
- "Medium"
|
- "Medium"
|
||||||
- "Naver"
|
- "Naver"
|
||||||
- "Netlify"
|
- "Netlify"
|
||||||
- "Notion"
|
|
||||||
- "Okta"
|
- "Okta"
|
||||||
- "OneLogin"
|
- "OneLogin"
|
||||||
- "Osso"
|
- "Osso"
|
||||||
@@ -91,7 +87,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,@auth/*"
|
npx envinfo --system --binaries --browsers --npmPackages "next,react,next-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:
|
||||||
|
|||||||
30
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
30
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
@@ -21,20 +21,20 @@ body:
|
|||||||
multiple: true
|
multiple: true
|
||||||
options:
|
options:
|
||||||
- "Custom adapter"
|
- "Custom adapter"
|
||||||
- "@auth/dgraph-adapter"
|
- "@next-auth/dgraph-adapter"
|
||||||
- "@auth/dynamodb-adapter"
|
- "@next-auth/dynamodb-adapter"
|
||||||
- "@auth/fauna-adapter"
|
- "@next-auth/fauna-adapter"
|
||||||
- "@auth/firebase-adapter"
|
- "@next-auth/firebase-adapter"
|
||||||
- "@auth/mikro-orm-adapter"
|
- "@next-auth/mikro-orm-adapter"
|
||||||
- "@auth/mongodb-adapter"
|
- "@next-auth/mongodb-adapter"
|
||||||
- "@auth/neo4j-adapter"
|
- "@next-auth/neo4j-adapter"
|
||||||
- "@auth/pouchdb-adapter"
|
- "@next-auth/pouchdb-adapter"
|
||||||
- "@auth/prisma-adapter"
|
- "@next-auth/prisma-adapter"
|
||||||
- "@auth/sequelize-adapter"
|
- "@next-auth/sequelize-adapter"
|
||||||
- "@auth/supabase-adapter"
|
- "@next-auth/supabase-adapter"
|
||||||
- "@auth/typeorm-adapter"
|
- "@next-auth/typeorm-legacy-adapter"
|
||||||
- "@auth/upstash-redis-adapter"
|
- "@next-auth/upstash-redis-adapter"
|
||||||
- "@auth/xata-adapter"
|
- "@next-auth/xata-adapter"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
@@ -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,@auth/*" && npx envinfo --npmPackages "@next-auth/*"
|
npx envinfo --system --binaries --browsers --npmPackages "next,react,next-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 closed after 7 days.
|
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.
|
||||||
|
|
||||||
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.)
|
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.
|
||||||
|
|
||||||
### **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,7 +41,13 @@ async function run() {
|
|||||||
label: { name: newLabel },
|
label: { name: newLabel },
|
||||||
} = payload
|
} = payload
|
||||||
|
|
||||||
if (pull_request || !issue?.body || !process.env.GITHUB_TOKEN) return
|
if (
|
||||||
|
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 =
|
||||||
@@ -72,9 +78,7 @@ async function run() {
|
|||||||
client.issues.createComment({
|
client.issues.createComment({
|
||||||
...issueCommon,
|
...issueCommon,
|
||||||
body: readFileSync(
|
body: readFileSync(
|
||||||
join(
|
join(process.env.GITHUB_ACTION_PATH, "repro.md"),
|
||||||
"/home/runner/work/next-auth/next-auth/.github/actions/issue-validator/repro.md"
|
|
||||||
),
|
|
||||||
"utf8"
|
"utf8"
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
|
|||||||
30
.github/issue-labeler.yml
vendored
30
.github/issue-labeler.yml
vendored
@@ -1,43 +1,43 @@
|
|||||||
# https://github.com/github/issue-labeler#basic-examples
|
# https://github.com/github/issue-labeler#basic-examples
|
||||||
|
|
||||||
dgraph:
|
dgraph:
|
||||||
- "@auth/dgraph-adapter"
|
- "@next-auth/dgraph-adapter"
|
||||||
|
|
||||||
dynamodb:
|
dynamodb:
|
||||||
- "@auth/dynamodb-adapter"
|
- "@next-auth/dynamodb-adapter"
|
||||||
|
|
||||||
fauna:
|
fauna:
|
||||||
- "@auth/fauna-adapter"
|
- "@next-auth/fauna-adapter"
|
||||||
|
|
||||||
firebase:
|
firebase:
|
||||||
- "@auth/firebase-adapter"
|
- "@next-auth/firebase-adapter"
|
||||||
|
|
||||||
mikro-orm:
|
mikro-orm:
|
||||||
- "@auth/mikro-orm-adapter"
|
- "@next-auth/mikro-orm-adapter"
|
||||||
|
|
||||||
mongodb:
|
mongodb:
|
||||||
- "@auth/mongodb-adapter"
|
- "@next-auth/mongodb-adapter"
|
||||||
|
|
||||||
neo4j:
|
neo4j:
|
||||||
- "@auth/neo4j-adapter"
|
- "@next-auth/neo4j-adapter"
|
||||||
|
|
||||||
pouchdb:
|
pouchdb:
|
||||||
- "@auth/pouchdb-adapter"
|
- "@next-auth/pouchdb-adapter"
|
||||||
|
|
||||||
prisma:
|
prisma:
|
||||||
- "@auth/prisma-adapter"
|
- "@next-auth/prisma-adapter"
|
||||||
|
|
||||||
sequelize:
|
sequelize:
|
||||||
- "@auth/sequelize-adapter"
|
- "@next-auth/sequelize-adapter"
|
||||||
|
|
||||||
supabase:
|
supabase:
|
||||||
- "@auth/supabase-adapter"
|
- "@next-auth/supabase-adapter"
|
||||||
|
|
||||||
typeorm:
|
typeorm-legacy:
|
||||||
- "@auth/typeorm-adapter"
|
- "@next-auth/typeorm-legacy-adapter"
|
||||||
|
|
||||||
upstash-redis:
|
upstash-redis:
|
||||||
- "@auth/upstash-redis-adapter"
|
- "@next-auth/upstash-redis-adapter"
|
||||||
|
|
||||||
xata:
|
xata:
|
||||||
- "@auth/xata-adapter"
|
- "@next-auth/xata-adapter"
|
||||||
|
|||||||
2
.github/pr-labeler.yml
vendored
2
.github/pr-labeler.yml
vendored
@@ -21,6 +21,6 @@ solidjs: ["packages/frameworks-solid-start/**/*"]
|
|||||||
supabase: ["packages/adapter-supabase/**/*"]
|
supabase: ["packages/adapter-supabase/**/*"]
|
||||||
svelte: ["packages/frameworks-sveltekit/**/*"]
|
svelte: ["packages/frameworks-sveltekit/**/*"]
|
||||||
test: ["**test**/*"]
|
test: ["**test**/*"]
|
||||||
typeorm: ["packages/adapter-typeorm/**/*"]
|
typeorm-legacy: ["packages/adapter-typeorm-legacy/**/*"]
|
||||||
upstash-redis: ["packages/adapter-upstash-redis/**/*"]
|
upstash-redis: ["packages/adapter-upstash-redis/**/*"]
|
||||||
xata: ["packages/adapter-xata/**/*"]
|
xata: ["packages/adapter-xata/**/*"]
|
||||||
|
|||||||
16
.github/sync.yml
vendored
16
.github/sync.yml
vendored
@@ -1,3 +1,5 @@
|
|||||||
|
# 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: .
|
||||||
@@ -5,23 +7,9 @@ nextauthjs/sveltekit-auth-example:
|
|||||||
- .github/FUNDING.yml
|
- .github/FUNDING.yml
|
||||||
- LICENSE
|
- LICENSE
|
||||||
|
|
||||||
nextauthjs/solid-start-auth-example:
|
|
||||||
- source: "apps/examples/solid-start"
|
|
||||||
dest: .
|
|
||||||
deleteOrphaned: true
|
|
||||||
- .github/FUNDING.yml
|
|
||||||
- LICENSE
|
|
||||||
|
|
||||||
nextauthjs/next-auth-gatsby-example:
|
nextauthjs/next-auth-gatsby-example:
|
||||||
- source: apps/playgrounds/gatsby
|
- source: apps/playgrounds/gatsby
|
||||||
dest: .
|
dest: .
|
||||||
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
|
|
||||||
|
|||||||
9
.github/version-pr/index.js
vendored
9
.github/version-pr/index.js
vendored
@@ -5,15 +5,14 @@ const core = require("@actions/core")
|
|||||||
try {
|
try {
|
||||||
const packageJSONPath = path.join(
|
const packageJSONPath = path.join(
|
||||||
process.cwd(),
|
process.cwd(),
|
||||||
`packages/${process.env.PACKAGE_PATH || "next-auth"}/package.json`
|
"packages/next-auth/package.json"
|
||||||
)
|
)
|
||||||
const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, "utf8"))
|
const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, "utf8"))
|
||||||
|
|
||||||
const sha8 = process.env.GITHUB_SHA.substring(0, 8)
|
const sha8 = process.env.GITHUB_SHA.substring(0, 8)
|
||||||
const prefix = "0.0.0-"
|
const prNumber = process.env.PR_NUMBER
|
||||||
const pr = process.env.PR_NUMBER
|
|
||||||
const source = pr ? `pr.${pr}` : "manual"
|
const packageVersion = `0.0.0-pr.${prNumber}.${sha8}`
|
||||||
const packageVersion = `${prefix}${source}.${sha8}`
|
|
||||||
packageJSON.version = packageVersion
|
packageJSON.version = packageVersion
|
||||||
core.setOutput("version", packageVersion)
|
core.setOutput("version", packageVersion)
|
||||||
fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON))
|
fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON))
|
||||||
|
|||||||
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 }}
|
||||||
|
|||||||
105
.github/workflows/release.yml
vendored
105
.github/workflows/release.yml
vendored
@@ -3,59 +3,11 @@ name: Release
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- "main"
|
||||||
- beta
|
- "beta"
|
||||||
- next
|
- "next"
|
||||||
- 3.x
|
- "3.x"
|
||||||
pull_request:
|
pull_request:
|
||||||
# TODO: Support latest releases
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
name:
|
|
||||||
type: choice
|
|
||||||
description: Package name (npm)
|
|
||||||
options:
|
|
||||||
- "@auth/core"
|
|
||||||
- "@auth/nextjs"
|
|
||||||
- "@auth/dgraph-adapter"
|
|
||||||
- "@auth/drizzle-adapter"
|
|
||||||
- "@auth/dynamodb-adapter"
|
|
||||||
- "@auth/fauna-adapter"
|
|
||||||
- "@auth/firebase-adapter"
|
|
||||||
- "@auth/mikro-orm-adapter"
|
|
||||||
- "@auth/mongodb-adapter"
|
|
||||||
- "@auth/neo4j-adapter"
|
|
||||||
- "@auth/pouchdb-adapter"
|
|
||||||
- "@auth/prisma-adapter"
|
|
||||||
- "@auth/sequelize-adapter"
|
|
||||||
- "@auth/supabase-adapter"
|
|
||||||
- "@auth/typeorm-adapter"
|
|
||||||
- "@auth/upstash-redis-adapter"
|
|
||||||
- "@auth/xata-adapter"
|
|
||||||
- "next-auth"
|
|
||||||
# TODO: Infer from package name
|
|
||||||
path:
|
|
||||||
type: choice
|
|
||||||
description: Directory name (packages/*)
|
|
||||||
options:
|
|
||||||
- "core"
|
|
||||||
- "frameworks-nextjs"
|
|
||||||
- "adapter-dgraph"
|
|
||||||
- "adapter-drizzle"
|
|
||||||
- "adapter-dynamodb"
|
|
||||||
- "adapter-fauna"
|
|
||||||
- "adapter-firebase"
|
|
||||||
- "adapter-mikro-orm"
|
|
||||||
- "adapter-mongodb"
|
|
||||||
- "adapter-neo4j"
|
|
||||||
- "adapter-pouchdb"
|
|
||||||
- "adapter-prisma"
|
|
||||||
- "adapter-sequelize"
|
|
||||||
- "adapter-supabase"
|
|
||||||
- "adapter-typeorm"
|
|
||||||
- "adapter-upstash-redis"
|
|
||||||
- "adapter-xata"
|
|
||||||
- "next-auth"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
@@ -83,22 +35,6 @@ 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:
|
||||||
@@ -173,36 +109,3 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
VERSION: ${{ steps.determine-version.outputs.version }}
|
VERSION: ${{ steps.determine-version.outputs.version }}
|
||||||
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
|
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
|
||||||
release-manual:
|
|
||||||
name: Publish manually
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
|
||||||
steps:
|
|
||||||
- name: Init
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Install pnpm
|
|
||||||
uses: pnpm/action-setup@v2.2.4
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
cache: "pnpm"
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install
|
|
||||||
- name: Determine version
|
|
||||||
uses: ./.github/version-pr
|
|
||||||
id: determine-version
|
|
||||||
env:
|
|
||||||
PACKAGE_PATH: ${{ github.event.inputs.path }}
|
|
||||||
- name: Publish to npm
|
|
||||||
run: |
|
|
||||||
pnpm build
|
|
||||||
cd packages/$PACKAGE_PATH
|
|
||||||
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> .npmrc
|
|
||||||
pnpm publish --no-git-checks --access public --tag experimental
|
|
||||||
echo "🎉 Experimental release published 📦️ on npm: https://npmjs.com/package/${{ github.event.inputs.name }}/v/${{ env.VERSION }}"
|
|
||||||
echo "Install via: pnpm add ${{ github.event.inputs.name }}@${{ env.VERSION }}"
|
|
||||||
env:
|
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
||||||
PACKAGE_PATH: ${{ github.event.inputs.path }}
|
|
||||||
VERSION: ${{ steps.determine-version.outputs.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
|
||||||
uses: balazsorban44/repo-file-sync-action@master
|
# Can update to v1 when https://github.com/BetaHuhn/repo-file-sync-action/issues/168 is resolved
|
||||||
|
uses: BetaHuhn/repo-file-sync-action@v1.16.5
|
||||||
with:
|
with:
|
||||||
GH_PAT: ${{ secrets.GH_PAT }}
|
GH_PAT: ${{ secrets.GH_PAT_CLASSIC }}
|
||||||
IS_FINE_GRAINED: true
|
|
||||||
SKIP_PR: true
|
SKIP_PR: true
|
||||||
ORIGINAL_MESSAGE: true
|
ORIGINAL_MESSAGE: true
|
||||||
|
|||||||
27
.gitignore
vendored
27
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
# Misc
|
# Misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.npmrc
|
||||||
.eslintcache
|
.eslintcache
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
@@ -11,9 +12,8 @@ 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
|
||||||
@@ -34,17 +34,18 @@ packages/next-auth/utils
|
|||||||
packages/next-auth/core
|
packages/next-auth/core
|
||||||
packages/next-auth/jwt
|
packages/next-auth/jwt
|
||||||
packages/next-auth/react
|
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/next
|
||||||
packages/*/*.js
|
packages/next-auth/middleware.d.ts
|
||||||
packages/*/*.d.ts
|
packages/next-auth/middleware.js
|
||||||
packages/*/*.d.ts.map
|
|
||||||
packages/*/lib
|
|
||||||
|
|
||||||
# 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
|
||||||
@@ -80,12 +81,14 @@ docs/.docusaurus
|
|||||||
docs/providers.json
|
docs/providers.json
|
||||||
|
|
||||||
# Core
|
# Core
|
||||||
packages/core/src/providers/oauth-types.ts
|
packages/core/*.js
|
||||||
|
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/core
|
docs/docs/reference/03-core
|
||||||
docs/docs/reference/sveltekit
|
docs/docs/reference/04-sveltekit
|
||||||
|
|
||||||
|
|
||||||
# SvelteKit
|
# SvelteKit
|
||||||
@@ -95,7 +98,3 @@ 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/core
|
docs/docs/reference/03-core
|
||||||
docs/docs/reference/sveltekit
|
docs/docs/reference/04-sveltekit
|
||||||
static
|
static
|
||||||
docs/providers.json
|
docs/providers.json
|
||||||
|
|
||||||
|
|||||||
22
.prettierrc.js
Normal file
22
.prettierrc.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// @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",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
# 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=
|
|
||||||
|
|
||||||
DESCOPE_ID=
|
|
||||||
DESCOPE_SECRET=
|
|
||||||
|
|
||||||
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
4
apps/dev/nextjs-v4/.vscode/settings.json
vendored
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"typescript.tsdk": "../../node_modules/.pnpm/typescript@4.8.4/node_modules/typescript/lib",
|
|
||||||
"typescript.enablePromptUseWorkspaceTsdk": true
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
# 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)
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
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 }
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
export default function RootLayout({
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<html>
|
|
||||||
<head></head>
|
|
||||||
<body>{children}</body>
|
|
||||||
</html>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import { getServerSession } from "next-auth/next"
|
|
||||||
|
|
||||||
export default async function Page() {
|
|
||||||
const session = await getServerSession()
|
|
||||||
return <pre>{JSON.stringify(session, null, 2)}</pre>
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
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>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
.footer {
|
|
||||||
margin-top: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navItems {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navItem {
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 1rem;
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
/* 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;
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import Header from 'components/header'
|
|
||||||
import Footer from 'components/footer'
|
|
||||||
|
|
||||||
export default function Layout ({ children }) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Header />
|
|
||||||
<main>
|
|
||||||
{children}
|
|
||||||
</main>
|
|
||||||
<Footer />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
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
6
apps/dev/nextjs-v4/next-env.d.ts
vendored
@@ -1,6 +0,0 @@
|
|||||||
/// <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.
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
/** @type {import("next").NextConfig} */
|
|
||||||
module.exports = {
|
|
||||||
webpack(config) {
|
|
||||||
config.experiments = { ...config.experiments, topLevelAwait: true }
|
|
||||||
return config
|
|
||||||
},
|
|
||||||
experimental: { appDir: true },
|
|
||||||
typescript: { ignoreBuildErrors: true },
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"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": {
|
|
||||||
"@auth/fauna-adapter": "workspace:*",
|
|
||||||
"@auth/prisma-adapter": "workspace:*",
|
|
||||||
"@auth/supabase-adapter": "workspace:*",
|
|
||||||
"@auth/typeorm-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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import { SessionProvider } from "next-auth/react"
|
|
||||||
import "./styles.css"
|
|
||||||
|
|
||||||
export default function App({ Component, pageProps }) {
|
|
||||||
return (
|
|
||||||
<SessionProvider session={pageProps.session}>
|
|
||||||
<Component {...pageProps} />
|
|
||||||
</SessionProvider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import Layout from '../components/layout'
|
|
||||||
|
|
||||||
export default function Page () {
|
|
||||||
return (
|
|
||||||
<Layout>
|
|
||||||
<h1>API Example</h1>
|
|
||||||
<p>The examples below show responses from the example API endpoints.</p>
|
|
||||||
<p><em>You must be signed in to see responses.</em></p>
|
|
||||||
<h2>Session</h2>
|
|
||||||
<p>/api/examples/session</p>
|
|
||||||
<iframe src='/api/examples/session' />
|
|
||||||
<h2>JSON Web Token</h2>
|
|
||||||
<p>/api/examples/jwt</p>
|
|
||||||
<iframe src='/api/examples/jwt' />
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
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 "@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 "@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 { TypeORMAdapter } from "@auth/typeorm-adapter"
|
|
||||||
// const adapter = TypeORMAdapter({
|
|
||||||
// type: "sqlite",
|
|
||||||
// name: "next-auth-test-memory",
|
|
||||||
// database: "./typeorm/dev.db",
|
|
||||||
// synchronize: true,
|
|
||||||
// })
|
|
||||||
|
|
||||||
// // Supabase
|
|
||||||
// import { SupabaseAdapter } from "@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)
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
// 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,19 +0,0 @@
|
|||||||
// This is an example of to protect an API route
|
|
||||||
import { getServerSession } from "next-auth/next"
|
|
||||||
import { authOptions } from "../auth/[...nextauth]"
|
|
||||||
|
|
||||||
export default async (req, res) => {
|
|
||||||
const session = await getServerSession(req, res, authOptions)
|
|
||||||
|
|
||||||
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.",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
// This is an example of how to access a session from an API route
|
|
||||||
import { getServerSession } from "next-auth/next"
|
|
||||||
import { authOptions } from "../auth/[...nextauth]"
|
|
||||||
|
|
||||||
export default async (req, res) => {
|
|
||||||
const session = await getServerSession(req, res, authOptions)
|
|
||||||
res.json(session)
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
// 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
|
|
||||||
import { getServerSession } from "next-auth/next"
|
|
||||||
import { authOptions } from "../auth/[...nextauth]"
|
|
||||||
import { createClient } from "@supabase/supabase-js"
|
|
||||||
|
|
||||||
export default async (req, res) => {
|
|
||||||
const session = await getServerSession(req, res, authOptions)
|
|
||||||
|
|
||||||
if (!session)
|
|
||||||
return res.send(JSON.stringify({ error: "No session!" }, null, 2))
|
|
||||||
|
|
||||||
const { supabaseAccessToken } = session
|
|
||||||
|
|
||||||
const supabase = createClient(
|
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
|
||||||
{
|
|
||||||
global: {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${supabaseAccessToken}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
// Now you can query with RLS enabled.
|
|
||||||
const { data, error } = await supabase.from("users").select("*")
|
|
||||||
|
|
||||||
res.send(JSON.stringify({ supabaseAccessToken, data, error }, null, 2))
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
// 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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
// 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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import Layout from "components/layout"
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
return (
|
|
||||||
<Layout>
|
|
||||||
<h1>Page protected by Middleware</h1>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
// 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,35 +0,0 @@
|
|||||||
import { useState, useEffect } from "react"
|
|
||||||
import { useSession } from "next-auth/react"
|
|
||||||
import Layout from "../components/layout"
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
const { status } = useSession({
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
const [content, setContent] = useState()
|
|
||||||
|
|
||||||
// Fetch content from protected route
|
|
||||||
useEffect(() => {
|
|
||||||
if (status === "loading") return
|
|
||||||
const fetchData = async () => {
|
|
||||||
const res = await fetch("/api/examples/protected")
|
|
||||||
const json = await res.json()
|
|
||||||
if (json.content) {
|
|
||||||
setContent(json.content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fetchData()
|
|
||||||
}, [status])
|
|
||||||
|
|
||||||
if (status === "loading") return <Layout>Loading...</Layout>
|
|
||||||
|
|
||||||
// If session exists, display content
|
|
||||||
return (
|
|
||||||
<Layout>
|
|
||||||
<h1>Protected Page</h1>
|
|
||||||
<p>
|
|
||||||
<strong>{content}</strong>
|
|
||||||
</p>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
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),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import Layout from "../components/layout"
|
|
||||||
import { useState, useEffect } from "react"
|
|
||||||
import { useSession } from "next-auth/react"
|
|
||||||
import { createClient } from "@supabase/supabase-js"
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
const { data: session } = useSession()
|
|
||||||
const [data, setData] = useState(null)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (session) {
|
|
||||||
console.log(session)
|
|
||||||
// User is logged in, let's fetch their data.
|
|
||||||
const { supabaseAccessToken } = session
|
|
||||||
const supabase = createClient(
|
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
|
||||||
{
|
|
||||||
global: {
|
|
||||||
headers: { Authorization: `Bearer ${supabaseAccessToken}` },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
// Fetch data with RLS enabled.
|
|
||||||
supabase
|
|
||||||
.from("users")
|
|
||||||
.select("*")
|
|
||||||
.then(({ data }) => setData(data))
|
|
||||||
}
|
|
||||||
}, [session])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout>
|
|
||||||
<h1>Fetch Data from Supabase with RLS</h1>
|
|
||||||
<h2>Client-side data fetching with RLS:</h2>
|
|
||||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
|
||||||
<h2>API Example</h2>
|
|
||||||
<p>
|
|
||||||
You can also use Supabase in API routes. See the code in the
|
|
||||||
`/pages/api/examples/supabase-rls.js` file.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<em>You must be signed in to see responses.</em>
|
|
||||||
</p>
|
|
||||||
<p>/api/examples/supabase-rls</p>
|
|
||||||
<iframe src="/api/examples/supabase-rls" />
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
// This is an example of how to protect content using server rendering
|
|
||||||
// and fetching data from Supabase with RLS enabled.
|
|
||||||
import { getServerSession } from "next-auth/next"
|
|
||||||
import { authOptions } from "./api/auth/[...nextauth]"
|
|
||||||
import { createClient } from "@supabase/supabase-js"
|
|
||||||
import Layout from "../components/layout"
|
|
||||||
import AccessDenied from "../components/access-denied"
|
|
||||||
|
|
||||||
export default function Page({ data, 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>Data fetched during SSR from Supabase with RSL enabled:</p>
|
|
||||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getServerSideProps(context) {
|
|
||||||
const session = await getServerSession(context.req, context.res, authOptions)
|
|
||||||
|
|
||||||
if (!session)
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
session,
|
|
||||||
data: null,
|
|
||||||
error: "No session",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const { supabaseAccessToken } = session
|
|
||||||
|
|
||||||
const supabase = createClient(
|
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
|
||||||
{
|
|
||||||
global: {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${supabaseAccessToken}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
// Now you can query with RLS enabled.
|
|
||||||
const { data, error } = await supabase.from("users").select("*")
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
session,
|
|
||||||
data,
|
|
||||||
error,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
-- 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");
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# Please do not edit this file manually
|
|
||||||
# It should be added in your version-control system (i.e. Git)
|
|
||||||
provider = "sqlite"
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
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])
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"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
20
apps/dev/nextjs-v4/types/nextauth.d.ts
vendored
@@ -1,20 +0,0 @@
|
|||||||
// 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,42 +9,20 @@ 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=
|
||||||
|
|
||||||
# Beyond Identity Provider
|
|
||||||
BEYOND_IDENTITY_CLIENT_ID=
|
|
||||||
BEYOND_IDENTITY_CLIENT_SECRET=
|
|
||||||
BEYOND_IDENTITY_ISSUER=
|
|
||||||
|
|
||||||
DESCOPE_ID=
|
|
||||||
DESCOPE_SECRET=
|
|
||||||
|
|
||||||
GITHUB_ID=
|
|
||||||
GITHUB_SECRET=
|
|
||||||
|
|
||||||
NOTION_ID=
|
|
||||||
NOTION_SECRET=
|
|
||||||
NOTION_REDIRECT_URI=
|
|
||||||
|
|
||||||
IDS4_ID=
|
|
||||||
IDS4_SECRET=
|
|
||||||
IDS4_ISSUER=
|
|
||||||
|
|
||||||
KEYCLOAK_ID=
|
KEYCLOAK_ID=
|
||||||
KEYCLOAK_SECRET=
|
KEYCLOAK_SECRET=
|
||||||
KEYCLOAK_ISSUER=
|
KEYCLOAK_ISSUER=
|
||||||
|
|
||||||
LINE_ID=
|
IDS4_ID=
|
||||||
LINE_SECRET=
|
IDS4_SECRET=
|
||||||
|
IDS4_ISSUER=
|
||||||
|
|
||||||
TRAKT_ID=
|
GITHUB_ID=
|
||||||
TRAKT_SECRET=
|
GITHUB_SECRET=
|
||||||
|
|
||||||
TWITCH_ID=
|
TWITCH_ID=
|
||||||
TWITCH_SECRET=
|
TWITCH_SECRET=
|
||||||
@@ -52,12 +30,11 @@ TWITCH_SECRET=
|
|||||||
TWITTER_ID=
|
TWITTER_ID=
|
||||||
TWITTER_SECRET=
|
TWITTER_SECRET=
|
||||||
|
|
||||||
WIKIMEDIA_ID=
|
LINE_ID=
|
||||||
WIKIMEDIA_SECRET=
|
LINE_SECRET=
|
||||||
|
|
||||||
# Yandex OAuth. new app -> https://oauth.yandex.com/client/new/id
|
TRAKT_ID=
|
||||||
YANDEX_ID=
|
TRAKT_SECRET=
|
||||||
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
|
||||||
@@ -70,9 +47,12 @@ 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
4
apps/dev/nextjs/.gitignore
vendored
@@ -1,4 +0,0 @@
|
|||||||
node_modules/
|
|
||||||
/test-results/
|
|
||||||
/playwright-report/
|
|
||||||
/playwright/.cache/
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { useSession } from "next-auth/react"
|
import { signIn, signOut, 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,7 +24,14 @@ 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 href="/api/auth/signin" className={styles.buttonPrimary}>
|
<a
|
||||||
|
href="/api/auth/signin"
|
||||||
|
className={styles.buttonPrimary}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
signIn()
|
||||||
|
}}
|
||||||
|
>
|
||||||
Sign in
|
Sign in
|
||||||
</a>
|
</a>
|
||||||
</>
|
</>
|
||||||
@@ -40,7 +47,14 @@ 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 href="/api/auth/signout" className={styles.button}>
|
<a
|
||||||
|
href="/api/auth/signout"
|
||||||
|
className={styles.button}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
signOut()
|
||||||
|
}}
|
||||||
|
>
|
||||||
Sign out
|
Sign out
|
||||||
</a>
|
</a>
|
||||||
</>
|
</>
|
||||||
|
|||||||
1
apps/dev/nextjs/next-env.d.ts
vendored
1
apps/dev/nextjs/next-env.d.ts
vendored
@@ -1,6 +1,5 @@
|
|||||||
/// <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,31 +9,28 @@
|
|||||||
"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/fauna-adapter": "workspace:*",
|
||||||
"@auth/fauna-adapter": "workspace:*",
|
"@next-auth/prisma-adapter": "workspace:*",
|
||||||
"@auth/prisma-adapter": "workspace:*",
|
"@next-auth/supabase-adapter": "workspace:*",
|
||||||
"@auth/supabase-adapter": "workspace:*",
|
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
||||||
"@auth/typeorm-adapter": "workspace:*",
|
|
||||||
"@prisma/client": "^3",
|
"@prisma/client": "^3",
|
||||||
"@supabase/supabase-js": "^2.0.5",
|
"@supabase/supabase-js": "^2.0.5",
|
||||||
"faunadb": "^4",
|
"faunadb": "^4",
|
||||||
"next": "13.3.0",
|
"next": "13.1.1",
|
||||||
"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.37",
|
"@types/react": "^18.0.15",
|
||||||
"@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,15 +2,12 @@ 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"
|
||||||
import Descope from "@auth/core/providers/descope"
|
|
||||||
import Discord from "@auth/core/providers/discord"
|
import Discord from "@auth/core/providers/discord"
|
||||||
import DuendeIDS6 from "@auth/core/providers/duende-identity-server6"
|
import DuendeIDS6 from "@auth/core/providers/duende-identity-server6"
|
||||||
// import Email from "@auth/core/providers/email"
|
// import Email from "@auth/core/providers/email"
|
||||||
@@ -26,7 +23,6 @@ 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"
|
||||||
@@ -35,29 +31,28 @@ 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"
|
||||||
|
|
||||||
// // Prisma
|
// // Prisma
|
||||||
// import { PrismaClient } from "@prisma/client"
|
// import { PrismaClient } from "@prisma/client"
|
||||||
// import { PrismaAdapter } from "@auth/prisma-adapter"
|
// import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||||
// const client = globalThis.prisma || new PrismaClient()
|
// const client = globalThis.prisma || new PrismaClient()
|
||||||
// if (process.env.NODE_ENV !== "production") globalThis.prisma = client
|
// if (process.env.NODE_ENV !== "production") globalThis.prisma = client
|
||||||
// const adapter = PrismaAdapter(client)
|
// const adapter = PrismaAdapter(client)
|
||||||
|
|
||||||
// // Fauna
|
// // Fauna
|
||||||
// import { Client as FaunaClient } from "faunadb"
|
// import { Client as FaunaClient } from "faunadb"
|
||||||
// import { FaunaAdapter } from "@auth/fauna-adapter"
|
// import { FaunaAdapter } from "@next-auth/fauna-adapter"
|
||||||
// const opts = { secret: process.env.FAUNA_SECRET, domain: process.env.FAUNA_DOMAIN }
|
// const opts = { secret: process.env.FAUNA_SECRET, domain: process.env.FAUNA_DOMAIN }
|
||||||
// const client = globalThis.fauna || new FaunaClient(opts)
|
// const client = globalThis.fauna || new FaunaClient(opts)
|
||||||
// if (process.env.NODE_ENV !== "production") globalThis.fauna = client
|
// if (process.env.NODE_ENV !== "production") globalThis.fauna = client
|
||||||
// const adapter = FaunaAdapter(client)
|
// const adapter = FaunaAdapter(client)
|
||||||
|
|
||||||
// // TypeORM
|
// // TypeORM
|
||||||
// import { TypeORMAdapter } from "@auth/typeorm-adapter"
|
// import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||||
// const adapter = TypeORMAdapter({
|
// const adapter = TypeORMLegacyAdapter({
|
||||||
// type: "sqlite",
|
// type: "sqlite",
|
||||||
// name: "next-auth-test-memory",
|
// name: "next-auth-test-memory",
|
||||||
// database: "./typeorm/dev.db",
|
// database: "./typeorm/dev.db",
|
||||||
@@ -65,7 +60,7 @@ import WorkOS from "@auth/core/providers/workos"
|
|||||||
// })
|
// })
|
||||||
|
|
||||||
// // Supabase
|
// // Supabase
|
||||||
// import { SupabaseAdapter } from "@auth/supabase-adapter"
|
// import { SupabaseAdapter } from "@next-auth/supabase-adapter"
|
||||||
// const adapter = SupabaseAdapter({
|
// const adapter = SupabaseAdapter({
|
||||||
// url: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
// url: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||||
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
||||||
@@ -73,7 +68,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",
|
||||||
@@ -87,7 +82,6 @@ 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,
|
||||||
@@ -95,20 +89,14 @@ 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 }),
|
||||||
Descope({ clientId: process.env.DESCOPE_ID, clientSecret: process.env.DESCOPE_SECRET }),
|
|
||||||
Discord({ clientId: process.env.DISCORD_ID, clientSecret: process.env.DISCORD_SECRET }),
|
Discord({ clientId: process.env.DISCORD_ID, clientSecret: process.env.DISCORD_SECRET }),
|
||||||
DuendeIDS6({ clientId: "interactive.confidential", clientSecret: "secret", issuer: "https://demo.duendesoftware.com" }),
|
DuendeIDS6({ clientId: "interactive.confidential", clientSecret: "secret", issuer: "https://demo.duendesoftware.com" }),
|
||||||
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, redirectProxy: process.env.AUTH_REDIRECT_PROXY_URL }),
|
GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET }),
|
||||||
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 }),
|
||||||
@@ -117,7 +105,6 @@ 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 }),
|
||||||
@@ -127,7 +114,6 @@ 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 }),
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
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;
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
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,11 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": false,
|
"strict": false,
|
||||||
@@ -23,17 +19,8 @@
|
|||||||
{
|
{
|
||||||
"name": "next"
|
"name": "next"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"strictNullChecks": true
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||||
"next-env.d.ts",
|
"exclude": ["node_modules", "jest.config.js"]
|
||||||
"**/*.ts",
|
}
|
||||||
"**/*.tsx",
|
|
||||||
".next/types/**/*.ts"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules",
|
|
||||||
"jest.config.js"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
"vite": "4.0.1"
|
"vite": "4.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth/core": "workspace:*",
|
"@auth/core": "latest",
|
||||||
"@auth/sveltekit": "workspace:*"
|
"@auth/sveltekit": "latest"
|
||||||
},
|
},
|
||||||
"type": "module"
|
"type": "module"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
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.now.sh/32
|
||||||
|
|
||||||
|
APPLE_ID=
|
||||||
|
APPLE_TEAM_ID=
|
||||||
|
APPLE_PRIVATE_KEY=
|
||||||
|
APPLE_KEY_ID=
|
||||||
|
|
||||||
AUTH0_ID=
|
AUTH0_ID=
|
||||||
AUTH0_SECRET=
|
AUTH0_SECRET=
|
||||||
AUTH0_ISSUER=
|
AUTH0_ISSUER=
|
||||||
|
|
||||||
DESCOPE_ID=
|
|
||||||
DESCOPE_SECRET=
|
|
||||||
|
|
||||||
FACEBOOK_ID=
|
FACEBOOK_ID=
|
||||||
FACEBOOK_SECRET=
|
FACEBOOK_SECRET=
|
||||||
|
|
||||||
@@ -20,3 +21,8 @@ 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,14 +1,9 @@
|
|||||||
> 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).
|
> 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).
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://authjs.dev" target="_blank">
|
<a href="https://next-auth.js.org" target="_blank"><img width="150px" src="https://next-auth.js.org/img/logo/logo-sm.png" /></a>
|
||||||
<img height="64" src="https://authjs.dev/img/logo/logo-sm.png" />
|
<h3 align="center">NextAuth.js Example App</h3>
|
||||||
</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>NextAuth.js</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>
|
||||||
@@ -30,14 +25,20 @@
|
|||||||
|
|
||||||
## 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
|
||||||
|
|
||||||
|
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.
|
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
|
||||||
|
|
||||||
### 1. Clone the repository and install dependencies
|
### 1. Clone the repository and install dependencies
|
||||||
@@ -97,13 +98,15 @@ npm run start
|
|||||||
|
|
||||||
### 5. Preparing for Production
|
### 5. Preparing for Production
|
||||||
|
|
||||||
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)
|
Follow the [Deployment documentation](https://next-auth.js.org/deployment)
|
||||||
|
|
||||||
[](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/main/docs/static/img/powered-by-vercel.svg" alt="Powered By Vercel" />
|
<img width="170px" src="https://raw.githubusercontent.com/nextauthjs/next-auth/canary/www/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 Auth.js Team</p>
|
<p align="left">Thanks to Vercel sponsoring this project by allowing it to be deployed for free for the entire NextAuth.js Team</p>
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
ISC
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
/** @type {import("next").NextConfig} */
|
|
||||||
module.exports = {
|
|
||||||
reactStrictMode: true,
|
|
||||||
}
|
|
||||||
@@ -20,12 +20,13 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "latest",
|
"next": "latest",
|
||||||
"next-auth": "latest",
|
"next-auth": "latest",
|
||||||
|
"nodemailer": "^6",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^18.16.2",
|
"@types/node": "^17",
|
||||||
"@types/react": "^18.2.0",
|
"@types/react": "^18.0.15",
|
||||||
"typescript": "^5.0.4"
|
"typescript": "^4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export default function Page() {
|
|||||||
<p>Only admin users can see this page.</p>
|
<p>Only admin users can see this page.</p>
|
||||||
<p>
|
<p>
|
||||||
To learn more about the NextAuth middleware see
|
To learn more about the NextAuth middleware see
|
||||||
<a href="https://next-auth.js.org/configuration/nextjs#middleware">
|
<a href="https://docs-git-misc-docs-nextauthjs.vercel.app/configuration/nextjs#middleware">
|
||||||
the docs
|
the docs
|
||||||
</a>
|
</a>
|
||||||
.
|
.
|
||||||
|
|||||||
@@ -4,17 +4,31 @@ import FacebookProvider from "next-auth/providers/facebook"
|
|||||||
import GithubProvider from "next-auth/providers/github"
|
import GithubProvider from "next-auth/providers/github"
|
||||||
import TwitterProvider from "next-auth/providers/twitter"
|
import TwitterProvider from "next-auth/providers/twitter"
|
||||||
import Auth0Provider from "next-auth/providers/auth0"
|
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
|
// For more information on each option (and a full list of options) go to
|
||||||
// https://next-auth.js.org/configuration/options
|
// https://next-auth.js.org/configuration/options
|
||||||
export const authOptions: NextAuthOptions = {
|
export const authOptions: NextAuthOptions = {
|
||||||
// https://next-auth.js.org/configuration/providers/oauth
|
// https://next-auth.js.org/configuration/providers/oauth
|
||||||
providers: [
|
providers: [
|
||||||
Auth0Provider({
|
/* EmailProvider({
|
||||||
clientId: process.env.AUTH0_ID,
|
server: process.env.EMAIL_SERVER,
|
||||||
clientSecret: process.env.AUTH0_SECRET,
|
from: process.env.EMAIL_FROM,
|
||||||
issuer: process.env.AUTH0_ISSUER,
|
}),
|
||||||
|
// 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({
|
FacebookProvider({
|
||||||
clientId: process.env.FACEBOOK_ID,
|
clientId: process.env.FACEBOOK_ID,
|
||||||
clientSecret: process.env.FACEBOOK_SECRET,
|
clientSecret: process.env.FACEBOOK_SECRET,
|
||||||
@@ -30,9 +44,16 @@ export const authOptions: NextAuthOptions = {
|
|||||||
TwitterProvider({
|
TwitterProvider({
|
||||||
clientId: process.env.TWITTER_ID,
|
clientId: process.env.TWITTER_ID,
|
||||||
clientSecret: process.env.TWITTER_SECRET,
|
clientSecret: process.env.TWITTER_SECRET,
|
||||||
version: "2.0",
|
}),
|
||||||
|
Auth0Provider({
|
||||||
|
clientId: process.env.AUTH0_ID,
|
||||||
|
clientSecret: process.env.AUTH0_SECRET,
|
||||||
|
issuer: process.env.AUTH0_ISSUER,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
theme: {
|
||||||
|
colorScheme: "light",
|
||||||
|
},
|
||||||
callbacks: {
|
callbacks: {
|
||||||
async jwt({ token }) {
|
async jwt({ token }) {
|
||||||
token.userRole = "admin"
|
token.userRole = "admin"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// This is an example of to protect an API route
|
// This is an example of to protect an API route
|
||||||
import { getServerSession } from "next-auth/next"
|
import { unstable_getServerSession } from "next-auth/next"
|
||||||
import { authOptions } from "../auth/[...nextauth]"
|
import { authOptions } from "../auth/[...nextauth]"
|
||||||
|
|
||||||
import type { NextApiRequest, NextApiResponse } from "next"
|
import type { NextApiRequest, NextApiResponse } from "next"
|
||||||
@@ -8,7 +8,7 @@ export default async function handler(
|
|||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse
|
res: NextApiResponse
|
||||||
) {
|
) {
|
||||||
const session = await getServerSession(req, res, authOptions)
|
const session = await unstable_getServerSession(req, res, authOptions)
|
||||||
|
|
||||||
if (session) {
|
if (session) {
|
||||||
return res.send({
|
return res.send({
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// 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 { getServerSession } from "next-auth"
|
import { unstable_getServerSession } from "next-auth"
|
||||||
import { authOptions } from "../auth/[...nextauth]"
|
import { authOptions } from "../auth/[...nextauth]"
|
||||||
|
|
||||||
import type { NextApiRequest, NextApiResponse } from "next"
|
import type { NextApiRequest, NextApiResponse } from "next"
|
||||||
@@ -8,6 +8,6 @@ export default async function handler(
|
|||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse
|
res: NextApiResponse
|
||||||
) {
|
) {
|
||||||
const session = await getServerSession(req, res, authOptions)
|
const session = await unstable_getServerSession(req, res, authOptions)
|
||||||
res.send(JSON.stringify(session, null, 2))
|
res.send(JSON.stringify(session, null, 2))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,22 @@
|
|||||||
import { getServerSession } from "next-auth/next"
|
import { unstable_getServerSession } from "next-auth/next"
|
||||||
import { authOptions } from "./api/auth/[...nextauth]"
|
import { authOptions } from "./api/auth/[...nextauth]"
|
||||||
import Layout from "../components/layout"
|
import Layout from "../components/layout"
|
||||||
|
|
||||||
import type { GetServerSidePropsContext } from "next"
|
import type { GetServerSidePropsContext } from "next"
|
||||||
import { useSession } from "next-auth/react"
|
import type { Session } from "next-auth"
|
||||||
|
|
||||||
export default function ServerSidePage() {
|
export default function ServerSidePage({ session }: { session: Session }) {
|
||||||
const { data: session } = useSession()
|
|
||||||
// As this page uses Server Side Rendering, the `session` will be already
|
// As this page uses Server Side Rendering, the `session` will be already
|
||||||
// populated on render without needing to go through a loading stage.
|
// populated on render without needing to go through a loading stage.
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<h1>Server Side Rendering</h1>
|
<h1>Server Side Rendering</h1>
|
||||||
<p>
|
<p>
|
||||||
This page uses the <strong>getServerSession()</strong> method in{" "}
|
This page uses the <strong>unstable_getServerSession()</strong> method
|
||||||
<strong>getServerSideProps()</strong>.
|
in <strong>getServerSideProps()</strong>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Using <strong>getServerSession()</strong> in{" "}
|
Using <strong>unstable_getServerSession()</strong> in{" "}
|
||||||
<strong>getServerSideProps()</strong> is the recommended approach if you
|
<strong>getServerSideProps()</strong> is the recommended approach if you
|
||||||
need to support Server Side Rendering with authentication.
|
need to support Server Side Rendering with authentication.
|
||||||
</p>
|
</p>
|
||||||
@@ -38,7 +37,11 @@ export default function ServerSidePage() {
|
|||||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
session: await getServerSession(context.req, context.res, authOptions),
|
session: await unstable_getServerSession(
|
||||||
|
context.req,
|
||||||
|
context.res,
|
||||||
|
authOptions
|
||||||
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
apps/examples/nextjs/process.d.ts
vendored
2
apps/examples/nextjs/process.d.ts
vendored
@@ -12,7 +12,5 @@ declare namespace NodeJS {
|
|||||||
GOOGLE_SECRET: string
|
GOOGLE_SECRET: string
|
||||||
AUTH0_ID: string
|
AUTH0_ID: string
|
||||||
AUTH0_SECRET: string
|
AUTH0_SECRET: string
|
||||||
DESCOPE_ID: string
|
|
||||||
DESCOPE_SECRET: string
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
GITHUB_ID=
|
|
||||||
GITHUB_SECRET=
|
|
||||||
AUTH_SECRET=
|
|
||||||
27
apps/examples/solid-start/.gitignore
vendored
27
apps/examples/solid-start/.gitignore
vendored
@@ -1,27 +0,0 @@
|
|||||||
dist
|
|
||||||
.solid
|
|
||||||
.output
|
|
||||||
.vercel
|
|
||||||
.netlify
|
|
||||||
netlify
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
|
|
||||||
# IDEs and editors
|
|
||||||
/.idea
|
|
||||||
.project
|
|
||||||
.classpath
|
|
||||||
*.launch
|
|
||||||
.settings/
|
|
||||||
|
|
||||||
# Temp
|
|
||||||
gitignore
|
|
||||||
|
|
||||||
# System Files
|
|
||||||
.DS_Store
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
.env
|
|
||||||
|
|
||||||
.vercel
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
> The example repository is maintained from a [monorepo](https://github.com/nextauthjs/next-auth/tree/main/apps/examples/solid-start). Pull Requests should be opened against [`nextauthjs/next-auth`](https://github.com/nextauthjs/next-auth).
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<br/>
|
|
||||||
<a href="https://authjs.dev" target="_blank">
|
|
||||||
<img height="64" src="https://authjs.dev/img/logo/logo-sm.png" />
|
|
||||||
</a>
|
|
||||||
<a href="https://start.solidjs.com" target="_blank">
|
|
||||||
<img height="64" src="https://www.solidjs.com/assets/logo-123b04bc.svg" />
|
|
||||||
</a>
|
|
||||||
<h3 align="center"><b>SolidStart Auth</b> - Example App</h3>
|
|
||||||
<p align="center">
|
|
||||||
Open Source. Full Stack. Own Your Data.
|
|
||||||
</p>
|
|
||||||
<p align="center" style="align: center;">
|
|
||||||
<a href="https://npm.im/@auth/solid-start">
|
|
||||||
<img alt="npm" src="https://img.shields.io/npm/v/@auth/solid-start?color=green&label=@auth/solid-start&style=flat-square">
|
|
||||||
</a>
|
|
||||||
<a href="https://bundlephobia.com/result?p=@auth/solid-start">
|
|
||||||
<img src="https://img.shields.io/bundlephobia/minzip/@auth/solid-start?label=size&style=flat-square" alt="Bundle Size"/>
|
|
||||||
</a>
|
|
||||||
<a href="https://www.npmtrends.com/@auth/solid-start">
|
|
||||||
<img src="https://img.shields.io/npm/dm/@auth/solid-start?label=downloads&style=flat-square" alt="Downloads" />
|
|
||||||
</a>
|
|
||||||
<a href="https://npm.im/@auth/solid-start">
|
|
||||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This is the official SolidStart Auth example for [Auth.js](https://authjs.dev).
|
|
||||||
|
|
||||||
|
|
||||||
## Getting started
|
|
||||||
|
|
||||||
You can follow the guide below, or click the following button to deploy this example to [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=solid-start-auth-example).
|
|
||||||
|
|
||||||
[](https://vercel.com/new/git/external?repository-url=https://github.com/nextauthjs/solid-start-auth-example&project-name=solid-start-auth-example&repository-name=solid-start-auth-example)
|
|
||||||
|
|
||||||
### Installing
|
|
||||||
|
|
||||||
```sh
|
|
||||||
pnpm add -D solid-start-vercel
|
|
||||||
```
|
|
||||||
```sh
|
|
||||||
npm i -D solid-start-vercel
|
|
||||||
```
|
|
||||||
```sh
|
|
||||||
yarn add -D solid-start-vercel
|
|
||||||
```
|
|
||||||
|
|
||||||
### Adding to Vite config
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import solid from "solid-start/vite";
|
|
||||||
import dotenv from "dotenv";
|
|
||||||
import { defineConfig } from "vite";
|
|
||||||
// @ts-expect-error no typing
|
|
||||||
import vercel from "solid-start-vercel";
|
|
||||||
|
|
||||||
export default defineConfig(() => {
|
|
||||||
dotenv.config();
|
|
||||||
return {
|
|
||||||
plugins: [solid({ ssr: true, adapter: vercel({ edge: false }) })],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### Environment Variables
|
|
||||||
|
|
||||||
- `ENABLE_VC_BUILD`=`1` .
|
|
||||||
|
|
||||||
### Finishing up
|
|
||||||
|
|
||||||
Create a GitHub repo and push the code to it, then deploy it to Vercel.
|
|
||||||
|
|
||||||
## Acknowledgements
|
|
||||||
|
|
||||||
<a href="https://vercel.com?utm_source=nextauthjs&utm_campaign=oss">
|
|
||||||
<img width="170px" src="https://raw.githubusercontent.com/nextauthjs/next-auth/main/docs/static/img/powered-by-vercel.svg" alt="Powered By Vercel" />
|
|
||||||
</a>
|
|
||||||
<p align="left">Thanks to Vercel sponsoring this project by allowing it to be deployed for free for the entire Auth.js Team</p>
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "my-app",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "solid-start dev",
|
|
||||||
"build": "solid-start build",
|
|
||||||
"start": "solid-start start",
|
|
||||||
"lint": "eslint --fix \"**/*.{ts,tsx,js,jsx}\""
|
|
||||||
},
|
|
||||||
"type": "module",
|
|
||||||
"devDependencies": {
|
|
||||||
"autoprefixer": "^10.4.13",
|
|
||||||
"postcss": "^8.4.19",
|
|
||||||
"solid-start-node": "^0.2.9",
|
|
||||||
"solid-start-vercel": "^0.2.9",
|
|
||||||
"tailwindcss": "^3.2.4",
|
|
||||||
"typescript": "^4.8.3",
|
|
||||||
"vite": "^3.1.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@auth/core": "latest",
|
|
||||||
"@solid-auth/next": "^0.0.19",
|
|
||||||
"@solidjs/meta": "^0.28.0",
|
|
||||||
"@solidjs/router": "^0.6.0",
|
|
||||||
"solid-js": "^1.5.7",
|
|
||||||
"solid-start": "^0.2.9",
|
|
||||||
"undici": "5.11.0",
|
|
||||||
"zod": "^3.19.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
plugins: {
|
|
||||||
tailwindcss: {},
|
|
||||||
autoprefixer: {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 664 B |
@@ -1,72 +0,0 @@
|
|||||||
import { Match, Show, Switch, type Component } from "solid-js";
|
|
||||||
import { createServerData$ } from "solid-start/server";
|
|
||||||
import { authOpts } from "~/routes/api/auth/[...solidauth]";
|
|
||||||
import { signIn, signOut } from "@solid-auth/next/client";
|
|
||||||
import { getSession } from "@solid-auth/next";
|
|
||||||
import { A } from "solid-start";
|
|
||||||
|
|
||||||
interface INavBarProps {}
|
|
||||||
|
|
||||||
const NavBar: Component<INavBarProps> = () => {
|
|
||||||
const session = useSession();
|
|
||||||
return (
|
|
||||||
<header class="flex flex-col w-full gap-2 fixed left-2/4 right-2/4 -translate-x-2/4 items-center">
|
|
||||||
<nav class="w-[70vw] sm:w-2/4 lg:w-[40%] p-5 bg-[#0000000d] flex items-center justify-between rounded-lg">
|
|
||||||
<Show
|
|
||||||
when={session()?.user}
|
|
||||||
keyed
|
|
||||||
fallback={
|
|
||||||
<>
|
|
||||||
<p class="text-lg font-semibold">You are not signed in</p>
|
|
||||||
<button
|
|
||||||
class="p-2.5 rounded-lg bg-[#346df1] text-white text-lg font-bold flex items-center justify-center"
|
|
||||||
onClick={() => signIn("github")}
|
|
||||||
>
|
|
||||||
Sign in
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{(us) => (
|
|
||||||
<>
|
|
||||||
<div class="flex gap-2 items-center">
|
|
||||||
<Show when={us.image} keyed>
|
|
||||||
{(im) => <img src={im} class="w-12 h-12 rounded-full" />}
|
|
||||||
</Show>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<h3 class="font-bold text-lg">Signed in as</h3>
|
|
||||||
<p class="text-lg font-semibold">{us.name}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
onClick={() => signOut()}
|
|
||||||
class="text-[#555] font-semibold underline"
|
|
||||||
>
|
|
||||||
Sign out
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Show>
|
|
||||||
</nav>
|
|
||||||
<div class="flex gap-2 items-center">
|
|
||||||
<A class="text-blue-500 font-bold underline" href="/">
|
|
||||||
Home
|
|
||||||
</A>
|
|
||||||
<A class="text-blue-500 font-bold underline" href="/protected">
|
|
||||||
Protected
|
|
||||||
</A>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default NavBar;
|
|
||||||
|
|
||||||
export const useSession = () => {
|
|
||||||
return createServerData$(
|
|
||||||
async (_, { request }) => {
|
|
||||||
return await getSession(request, authOpts);
|
|
||||||
},
|
|
||||||
{ key: () => ["auth_user"] }
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { default } from "./NavBar";
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import { type Session } from "@auth/core";
|
|
||||||
import { getSession } from "@solid-auth/next";
|
|
||||||
import { Component, Show } from "solid-js";
|
|
||||||
import { useRouteData } from "solid-start";
|
|
||||||
import { createServerData$, redirect } from "solid-start/server";
|
|
||||||
import { authOpts } from "~/routes/api/auth/[...solidauth]";
|
|
||||||
|
|
||||||
const Protected = (Comp: IProtectedComponent) => {
|
|
||||||
const routeData = () => {
|
|
||||||
return createServerData$(
|
|
||||||
async (_, event) => {
|
|
||||||
const session = await getSession(event.request, authOpts);
|
|
||||||
if (!session || !session.user) {
|
|
||||||
throw redirect("/");
|
|
||||||
}
|
|
||||||
return session;
|
|
||||||
},
|
|
||||||
{ key: () => ["auth_user"] }
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
routeData,
|
|
||||||
Page: () => {
|
|
||||||
const session = useRouteData<typeof routeData>();
|
|
||||||
return (
|
|
||||||
<Show when={session()} keyed>
|
|
||||||
{(sess) => <Comp {...sess} />}
|
|
||||||
</Show>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
type IProtectedComponent = Component<Session>;
|
|
||||||
|
|
||||||
export default Protected;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { default } from "./Protected";
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export { default as NavBar } from "./NavBar";
|
|
||||||
export { default as Protected } from "./Protected";
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import { mount, StartClient } from "solid-start/entry-client";
|
|
||||||
|
|
||||||
mount(() => <StartClient />, document);
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import {
|
|
||||||
StartServer,
|
|
||||||
createHandler,
|
|
||||||
renderAsync,
|
|
||||||
} from "solid-start/entry-server";
|
|
||||||
|
|
||||||
export default createHandler(
|
|
||||||
renderAsync((event) => <StartServer event={event} />)
|
|
||||||
);
|
|
||||||
24
apps/examples/solid-start/src/env/client.ts
vendored
24
apps/examples/solid-start/src/env/client.ts
vendored
@@ -1,24 +0,0 @@
|
|||||||
import type { ZodFormattedError } from "zod";
|
|
||||||
import { clientScheme } from "./schema";
|
|
||||||
|
|
||||||
export const formatErrors = (
|
|
||||||
errors: ZodFormattedError<Map<string, string>, string>
|
|
||||||
) =>
|
|
||||||
Object.entries(errors)
|
|
||||||
.map(([name, value]) => {
|
|
||||||
if (value && "_errors" in value)
|
|
||||||
return `${name}: ${value._errors.join(", ")}\n`;
|
|
||||||
})
|
|
||||||
.filter(Boolean);
|
|
||||||
|
|
||||||
const env = clientScheme.safeParse(import.meta.env);
|
|
||||||
|
|
||||||
if (env.success === false) {
|
|
||||||
console.error(
|
|
||||||
"❌ Invalid environment variables:\n",
|
|
||||||
...formatErrors(env.error.format())
|
|
||||||
);
|
|
||||||
throw new Error("Invalid environment variables");
|
|
||||||
}
|
|
||||||
|
|
||||||
export const clientEnv = env.data;
|
|
||||||
15
apps/examples/solid-start/src/env/schema.ts
vendored
15
apps/examples/solid-start/src/env/schema.ts
vendored
@@ -1,15 +0,0 @@
|
|||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
export const serverScheme = z.object({
|
|
||||||
NODE_ENV: z
|
|
||||||
.enum(["development", "production", "test"])
|
|
||||||
.default("development"),
|
|
||||||
GITHUB_ID: z.string(),
|
|
||||||
GITHUB_SECRET: z.string(),
|
|
||||||
AUTH_SECRET: z.string(),
|
|
||||||
NEXTAUTH_URL: z.string().optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const clientScheme = z.object({
|
|
||||||
MODE: z.enum(["development", "production", "test"]).default("development"),
|
|
||||||
});
|
|
||||||
24
apps/examples/solid-start/src/env/server.ts
vendored
24
apps/examples/solid-start/src/env/server.ts
vendored
@@ -1,24 +0,0 @@
|
|||||||
import { serverScheme } from "./schema";
|
|
||||||
import type { ZodFormattedError } from "zod";
|
|
||||||
|
|
||||||
export const formatErrors = (
|
|
||||||
errors: ZodFormattedError<Map<string, string>, string>
|
|
||||||
) =>
|
|
||||||
Object.entries(errors)
|
|
||||||
.map(([name, value]) => {
|
|
||||||
if (value && "_errors" in value)
|
|
||||||
return `${name}: ${value._errors.join(", ")}\n`;
|
|
||||||
})
|
|
||||||
.filter(Boolean);
|
|
||||||
|
|
||||||
const env = serverScheme.safeParse(process.env);
|
|
||||||
|
|
||||||
if (env.success === false) {
|
|
||||||
console.error(
|
|
||||||
"❌ Invalid environment variables:\n",
|
|
||||||
...formatErrors(env.error.format())
|
|
||||||
);
|
|
||||||
throw new Error("Invalid environment variables");
|
|
||||||
}
|
|
||||||
|
|
||||||
export const serverEnv = env.data;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// @refresh reload
|
|
||||||
import "./root.css";
|
|
||||||
import { Suspense } from "solid-js";
|
|
||||||
import {
|
|
||||||
Body,
|
|
||||||
ErrorBoundary,
|
|
||||||
FileRoutes,
|
|
||||||
Head,
|
|
||||||
Html,
|
|
||||||
Meta,
|
|
||||||
Routes,
|
|
||||||
Scripts,
|
|
||||||
Title,
|
|
||||||
} from "solid-start";
|
|
||||||
import { NavBar } from "./components";
|
|
||||||
|
|
||||||
export default function Root() {
|
|
||||||
return (
|
|
||||||
<Html lang="en">
|
|
||||||
<Head>
|
|
||||||
<Title>Create JD App</Title>
|
|
||||||
<Meta charset="utf-8" />
|
|
||||||
<Meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
</Head>
|
|
||||||
<Body>
|
|
||||||
<Suspense>
|
|
||||||
<NavBar />
|
|
||||||
<div class="py-44 px-8">
|
|
||||||
<ErrorBoundary>
|
|
||||||
<Routes>
|
|
||||||
<FileRoutes />
|
|
||||||
</Routes>
|
|
||||||
</ErrorBoundary>
|
|
||||||
</div>
|
|
||||||
</Suspense>
|
|
||||||
<Scripts />
|
|
||||||
</Body>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import { SolidAuth, type SolidAuthConfig } from "@solid-auth/next";
|
|
||||||
import GitHub from "@auth/core/providers/github";
|
|
||||||
import { serverEnv } from "~/env/server";
|
|
||||||
import { type APIEvent } from "solid-start";
|
|
||||||
|
|
||||||
export const authOpts: SolidAuthConfig = {
|
|
||||||
providers: [
|
|
||||||
GitHub({
|
|
||||||
clientId: serverEnv.GITHUB_ID,
|
|
||||||
clientSecret: serverEnv.GITHUB_SECRET,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
debug: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const { GET, POST } = SolidAuth(authOpts);
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
import { type ParentComponent } from "solid-js";
|
|
||||||
import { A, Title, useRouteData } from "solid-start";
|
|
||||||
import { createServerData$ } from "solid-start/server";
|
|
||||||
import { authOpts } from "./api/auth/[...solidauth]";
|
|
||||||
import { getSession } from "@solid-auth/next";
|
|
||||||
|
|
||||||
export const routeData = () => {
|
|
||||||
return createServerData$(
|
|
||||||
async (_, { request }) => {
|
|
||||||
return await getSession(request, authOpts);
|
|
||||||
},
|
|
||||||
{ key: () => ["auth_user"] }
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const Home: ParentComponent = () => {
|
|
||||||
const user = useRouteData<typeof routeData>();
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Title>Create JD App</Title>
|
|
||||||
<div class="flex flex-col gap-2 items-center">
|
|
||||||
<h1 class="text-4xl font-bold">SolidStart Auth Example</h1>
|
|
||||||
<p class="font-semibold text-md max-w-[40rem]">
|
|
||||||
This is an example site to demonstrate how to use{" "}
|
|
||||||
<A
|
|
||||||
href="https://start.solidjs.com/getting-started/what-is-solidstart"
|
|
||||||
class="text-blue-500 underline font-bold"
|
|
||||||
>
|
|
||||||
SolidStart
|
|
||||||
</A>{" "}
|
|
||||||
with{" "}
|
|
||||||
<A
|
|
||||||
href="https://authjs.dev/reference/solidstart"
|
|
||||||
class="text-blue-500 underline font-bold"
|
|
||||||
>
|
|
||||||
SolidStart Auth
|
|
||||||
</A>{" "}
|
|
||||||
for authentication.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Home;
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { Protected } from "~/components";
|
|
||||||
|
|
||||||
export const { routeData, Page } = Protected((session) => {
|
|
||||||
return (
|
|
||||||
<main class="flex flex-col gap-2 items-center">
|
|
||||||
<h1>This is a protected route</h1>
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Page;
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user