mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
154 Commits
feat/nextj
...
@auth/core
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
645d003d49 | ||
|
|
3f296615c5 | ||
|
|
a7842077ec | ||
|
|
b2e5b9f6a8 | ||
|
|
0681531627 | ||
|
|
ea81c467e9 | ||
|
|
bf2835d38f | ||
|
|
89d230666b | ||
|
|
f86e56f78a | ||
|
|
fe20b943ae | ||
|
|
4678c4d4fc | ||
|
|
3eb3f8f107 | ||
|
|
7fd03f38e3 | ||
|
|
ae44b72765 | ||
|
|
a996ab57e8 | ||
|
|
ebdeaf740d | ||
|
|
c5c8a81462 | ||
|
|
61d30f3dcd | ||
|
|
a9180a752b | ||
|
|
6c4180146e | ||
|
|
ec6c4ea2be | ||
|
|
3dfc86334e | ||
|
|
01d6019638 | ||
|
|
4730429a9f | ||
|
|
a49236ef62 | ||
|
|
96ade948ef | ||
|
|
550507b2d1 | ||
|
|
1eddcf643c | ||
|
|
17d71a04d6 | ||
|
|
3c65e264af | ||
|
|
28d8d4894d | ||
|
|
c6b98a8f08 | ||
|
|
d042f933c6 | ||
|
|
3a85de2c5f | ||
|
|
d47b56743e | ||
|
|
363440e515 | ||
|
|
60c5037ee1 | ||
|
|
97394baed1 | ||
|
|
f94abb8f70 | ||
|
|
bbfc11e74c | ||
|
|
2a70514df1 | ||
|
|
96d666465f | ||
|
|
ecbf0be22e | ||
|
|
87ec13bd00 | ||
|
|
c0f9af4c56 | ||
|
|
c7b36f45a3 | ||
|
|
68ff69f9eb | ||
|
|
23c0a393da | ||
|
|
f130f62a91 | ||
|
|
c111b436d2 | ||
|
|
ea895b8864 | ||
|
|
cfedc3b1a3 | ||
|
|
287a5fc05a | ||
|
|
f3ad659e91 | ||
|
|
48b9a0203e | ||
|
|
39fbccb783 | ||
|
|
f207e94146 | ||
|
|
b845729cdb | ||
|
|
e459d2d7e2 | ||
|
|
db1fd9007c | ||
|
|
0439fc5fc6 | ||
|
|
d0dd2ababc | ||
|
|
ba58d48dba | ||
|
|
a8d76ed440 | ||
|
|
3d7b8720db | ||
|
|
1e886b97bc | ||
|
|
ecb14ccecd | ||
|
|
8cee24d4ab | ||
|
|
0189a197be | ||
|
|
c44bf75c65 | ||
|
|
cf13b6c7e3 | ||
|
|
dc1a79e547 | ||
|
|
78964c115b | ||
|
|
7fa51e2a61 | ||
|
|
a79774f6e8 | ||
|
|
f779f05906 | ||
|
|
3245c02eac | ||
|
|
a8dfc8ebb1 | ||
|
|
1b80a18dd4 | ||
|
|
50a88bb878 | ||
|
|
a359a562ce | ||
|
|
7edb9cf53f | ||
|
|
018b086c4f | ||
|
|
173000a068 | ||
|
|
8fcd46b0fc | ||
|
|
d5d1313914 | ||
|
|
3285d04241 | ||
|
|
fe442522ef | ||
|
|
6c9dfff45f | ||
|
|
ef50916ec2 | ||
|
|
8e771a2993 | ||
|
|
06a7149b66 | ||
|
|
662e0942cb | ||
|
|
91c71a175b | ||
|
|
3b8c75297b | ||
|
|
5d06fa5852 | ||
|
|
e7a52077c5 | ||
|
|
6e4516a9f8 | ||
|
|
8a0b11fcd6 | ||
|
|
f925e0c2a5 | ||
|
|
de4e20cc04 | ||
|
|
65f4b9c942 | ||
|
|
1d29b0d220 | ||
|
|
cd92aa0c82 | ||
|
|
d414e01181 | ||
|
|
43deda5bfb | ||
|
|
7e79d8c509 | ||
|
|
ab051162a7 | ||
|
|
87298a0150 | ||
|
|
d6abccd9a0 | ||
|
|
2f35daae37 | ||
|
|
a0f3b04c43 | ||
|
|
c7dec376a1 | ||
|
|
925a52e0ec | ||
|
|
2318e44de4 | ||
|
|
d73812bce5 | ||
|
|
ee36d09a08 | ||
|
|
0cb7fd2e7c | ||
|
|
3b414bd7b5 | ||
|
|
37bb6ebd2c | ||
|
|
2ecf52c342 | ||
|
|
cda07c239e | ||
|
|
fa60b79abe | ||
|
|
39e1a76e8f | ||
|
|
953ef9d04a | ||
|
|
94f3031765 | ||
|
|
ad7bf07ddf | ||
|
|
f30308ac30 | ||
|
|
6eaaeb15e9 | ||
|
|
8b3f0696a5 | ||
|
|
c69a157832 | ||
|
|
60af446338 | ||
|
|
ce85444760 | ||
|
|
142abe3eea | ||
|
|
da211e6cbe | ||
|
|
79ad6156ed | ||
|
|
28f287d63e | ||
|
|
1ab77d0e11 | ||
|
|
787c1ff7d0 | ||
|
|
208b3b4a43 | ||
|
|
c4f6330f70 | ||
|
|
44127068e1 | ||
|
|
9e3f1aacf7 | ||
|
|
83051c6862 | ||
|
|
f1acab67e6 | ||
|
|
6a31ed3216 | ||
|
|
0998fc0b98 | ||
|
|
bd20d750c2 | ||
|
|
8e29b4df0c | ||
|
|
9632a56d45 | ||
|
|
12161b9613 | ||
|
|
a3b5276a5a | ||
|
|
7c1078b9a9 | ||
|
|
37d3461155 |
1
.github/ISSUE_TEMPLATE/2_bug_provider.yml
vendored
1
.github/ISSUE_TEMPLATE/2_bug_provider.yml
vendored
@@ -37,6 +37,7 @@ body:
|
||||
- "Bungie"
|
||||
- "Cognito"
|
||||
- "Coinbase"
|
||||
- "Descope"
|
||||
- "Discord"
|
||||
- "Dropbox"
|
||||
- "EVE Online"
|
||||
|
||||
31
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
31
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
@@ -21,20 +21,23 @@ body:
|
||||
multiple: true
|
||||
options:
|
||||
- "Custom adapter"
|
||||
- "@next-auth/dgraph-adapter"
|
||||
- "@next-auth/dynamodb-adapter"
|
||||
- "@next-auth/fauna-adapter"
|
||||
- "@next-auth/firebase-adapter"
|
||||
- "@next-auth/mikro-orm-adapter"
|
||||
- "@next-auth/mongodb-adapter"
|
||||
- "@next-auth/neo4j-adapter"
|
||||
- "@next-auth/pouchdb-adapter"
|
||||
- "@next-auth/prisma-adapter"
|
||||
- "@next-auth/sequelize-adapter"
|
||||
- "@next-auth/supabase-adapter"
|
||||
- "@next-auth/typeorm-legacy-adapter"
|
||||
- "@next-auth/upstash-redis-adapter"
|
||||
- "@next-auth/xata-adapter"
|
||||
- "@auth/dgraph-adapter"
|
||||
- "@auth/drizzle-adapter"
|
||||
- "@auth/dynamodb-adapter"
|
||||
- "@auth/drizzle-adapter"
|
||||
- "@auth/fauna-adapter"
|
||||
- "@auth/firebase-adapter"
|
||||
- "@auth/kysely-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"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
36
.github/issue-labeler.yml
vendored
36
.github/issue-labeler.yml
vendored
@@ -1,43 +1,49 @@
|
||||
# https://github.com/github/issue-labeler#basic-examples
|
||||
|
||||
dgraph:
|
||||
- "@next-auth/dgraph-adapter"
|
||||
- "@auth/dgraph-adapter"
|
||||
|
||||
drizzle:
|
||||
- "@auth/drizzle-adapter"
|
||||
|
||||
dynamodb:
|
||||
- "@next-auth/dynamodb-adapter"
|
||||
- "@auth/dynamodb-adapter"
|
||||
|
||||
fauna:
|
||||
- "@next-auth/fauna-adapter"
|
||||
- "@auth/fauna-adapter"
|
||||
|
||||
firebase:
|
||||
- "@next-auth/firebase-adapter"
|
||||
- "@auth/firebase-adapter"
|
||||
|
||||
kysely:
|
||||
- "@auth/kysely-adapter"
|
||||
|
||||
mikro-orm:
|
||||
- "@next-auth/mikro-orm-adapter"
|
||||
- "@auth/mikro-orm-adapter"
|
||||
|
||||
mongodb:
|
||||
- "@next-auth/mongodb-adapter"
|
||||
- "@auth/mongodb-adapter"
|
||||
|
||||
neo4j:
|
||||
- "@next-auth/neo4j-adapter"
|
||||
- "@auth/neo4j-adapter"
|
||||
|
||||
pouchdb:
|
||||
- "@next-auth/pouchdb-adapter"
|
||||
- "@auth/pouchdb-adapter"
|
||||
|
||||
prisma:
|
||||
- "@next-auth/prisma-adapter"
|
||||
- "@auth/prisma-adapter"
|
||||
|
||||
sequelize:
|
||||
- "@next-auth/sequelize-adapter"
|
||||
- "@auth/sequelize-adapter"
|
||||
|
||||
supabase:
|
||||
- "@next-auth/supabase-adapter"
|
||||
- "@auth/supabase-adapter"
|
||||
|
||||
typeorm-legacy:
|
||||
- "@next-auth/typeorm-legacy-adapter"
|
||||
typeorm:
|
||||
- "@auth/typeorm-adapter"
|
||||
|
||||
upstash-redis:
|
||||
- "@next-auth/upstash-redis-adapter"
|
||||
- "@auth/upstash-redis-adapter"
|
||||
|
||||
xata:
|
||||
- "@next-auth/xata-adapter"
|
||||
- "@auth/xata-adapter"
|
||||
|
||||
3
.github/pr-labeler.yml
vendored
3
.github/pr-labeler.yml
vendored
@@ -15,12 +15,13 @@ neo4j: ["packages/adapter-neo4j/**/*"]
|
||||
playgrounds: ["apps/playgrounds/**/*"]
|
||||
pouchdb: ["packages/adapter-pouchdb/**/*"]
|
||||
prisma: ["packages/adapter-prisma/**/*"]
|
||||
kysely: ["packages/adapter-kysely/**/*"]
|
||||
providers: ["packages/core/src/providers/**/*"]
|
||||
sequelize: ["packages/adapter-sequelize/**/*"]
|
||||
solidjs: ["packages/frameworks-solid-start/**/*"]
|
||||
supabase: ["packages/adapter-supabase/**/*"]
|
||||
svelte: ["packages/frameworks-sveltekit/**/*"]
|
||||
test: ["**test**/*"]
|
||||
typeorm-legacy: ["packages/adapter-typeorm-legacy/**/*"]
|
||||
typeorm: ["packages/adapter-typeorm/**/*"]
|
||||
upstash-redis: ["packages/adapter-upstash-redis/**/*"]
|
||||
xata: ["packages/adapter-xata/**/*"]
|
||||
|
||||
9
.github/version-pr/index.js
vendored
9
.github/version-pr/index.js
vendored
@@ -5,14 +5,15 @@ const core = require("@actions/core")
|
||||
try {
|
||||
const packageJSONPath = path.join(
|
||||
process.cwd(),
|
||||
"packages/next-auth/package.json"
|
||||
`packages/${process.env.PACKAGE_PATH || "next-auth"}/package.json`
|
||||
)
|
||||
const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, "utf8"))
|
||||
|
||||
const sha8 = process.env.GITHUB_SHA.substring(0, 8)
|
||||
const prNumber = process.env.PR_NUMBER
|
||||
|
||||
const packageVersion = `0.0.0-pr.${prNumber}.${sha8}`
|
||||
const prefix = "0.0.0-"
|
||||
const pr = process.env.PR_NUMBER
|
||||
const source = pr ? `pr.${pr}` : "manual"
|
||||
const packageVersion = `${prefix}${source}.${sha8}`
|
||||
packageJSON.version = packageVersion
|
||||
core.setOutput("version", packageVersion)
|
||||
fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON))
|
||||
|
||||
94
.github/workflows/release.yml
vendored
94
.github/workflows/release.yml
vendored
@@ -8,6 +8,58 @@ on:
|
||||
- next
|
||||
- 3.x
|
||||
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"
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
FORCE_COLOR: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
@@ -24,16 +76,17 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
- name: Run tests
|
||||
run: pnpm test
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
UPSTASH_REDIS_URL: ${{ secrets.UPSTASH_REDIS_URL }}
|
||||
UPSTASH_REDIS_KEY: ${{ secrets.UPSTASH_REDIS_KEY }}
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
# - name: Run E2E tests
|
||||
# if: github.repository == 'nextauthjs/next-auth'
|
||||
# run: pnpm e2e
|
||||
@@ -42,7 +95,7 @@ jobs:
|
||||
# AUTH0_USERNAME: ${{ secrets.AUTH0_USERNAME }}
|
||||
# AUTH0_PASSWORD: ${{ secrets.AUTH0_PASSWORD }}
|
||||
# TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
# TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
# TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
# - name: Upload E2E artifacts
|
||||
# if: github.repository == 'nextauthjs/next-auth'
|
||||
# uses: actions/upload-artifact@v3
|
||||
@@ -73,6 +126,7 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Publish to npm and GitHub
|
||||
@@ -97,6 +151,7 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Determine version
|
||||
@@ -122,3 +177,36 @@ jobs:
|
||||
env:
|
||||
VERSION: ${{ steps.determine-version.outputs.version }}
|
||||
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 }}
|
||||
|
||||
21
.gitignore
vendored
21
.gitignore
vendored
@@ -6,6 +6,8 @@
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
packages/*/.npmrc
|
||||
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
@@ -26,10 +28,19 @@ dist
|
||||
# Generated files
|
||||
.docusaurus
|
||||
.cache-loader
|
||||
|
||||
packages/next-auth/providers
|
||||
packages/next-auth/src/providers/oauth-types.ts
|
||||
packages/next-auth/client
|
||||
packages/next-auth/css
|
||||
packages/next-auth/utils
|
||||
packages/next-auth/core
|
||||
packages/next-auth/jwt
|
||||
packages/next-auth/react
|
||||
packages/next-auth/next
|
||||
packages/*/*.js
|
||||
packages/*/*.d.ts
|
||||
packages/*/*.d.ts.map
|
||||
packages/*/lib
|
||||
|
||||
# Development app
|
||||
apps/dev/src/css
|
||||
@@ -56,6 +67,7 @@ packages/adapter-prisma/prisma/dev.db
|
||||
packages/adapter-prisma/prisma/migrations
|
||||
db.sqlite
|
||||
packages/adapter-supabase/supabase/.branches
|
||||
packages/adapter-drizzle/.drizzle
|
||||
|
||||
# Tests
|
||||
coverage
|
||||
@@ -77,10 +89,7 @@ packages/core/providers
|
||||
packages/core/src/lib/pages/styles.ts
|
||||
docs/docs/reference/core
|
||||
docs/docs/reference/sveltekit
|
||||
docs/docs/reference/next-auth
|
||||
|
||||
# Next.js
|
||||
packages/next-auth/lib
|
||||
|
||||
# SvelteKit
|
||||
packages/frameworks-sveltekit/index.*
|
||||
@@ -91,5 +100,7 @@ packages/frameworks-sveltekit/vite.config.js.timestamp-*
|
||||
packages/frameworks-sveltekit/vite.config.ts.timestamp-*
|
||||
|
||||
# Adapters
|
||||
docs/docs/reference/adapter
|
||||
|
||||
docs/docs/reference/adapter
|
||||
## Drizzle migration folder
|
||||
.drizzle
|
||||
@@ -40,6 +40,10 @@ packages/core/src/lib/pages/styles.ts
|
||||
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
|
||||
|
||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"files.exclude": {
|
||||
"packages/core/{lib,providers,*.js,*.d.ts*}": true,
|
||||
"packages/next-auth/{lib,*.js,*.d.ts*}": true,
|
||||
"packages/core/{lib,providers,*.js,*.d.ts,*.d.ts.map}": true,
|
||||
"packages/next-auth/{client,core,css,jwt,next,providers,react,utils,*.js,*.d.ts}": true
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"openInGitHub.remote.branch": "main"
|
||||
}
|
||||
}
|
||||
|
||||
153
README.md
Normal file
153
README.md
Normal file
@@ -0,0 +1,153 @@
|
||||
<p align="center">
|
||||
<br/>
|
||||
<a href="https://authjs.dev" target="_blank"><img width="96px" src="https://authjs.dev/img/logo/logo-sm.png" /></a>
|
||||
<h3 align="center">Auth.js</h3>
|
||||
<p align="center">Authentication for the Web.</p>
|
||||
<p align="center">Open Source. Full Stack. Own Your Data.</p>
|
||||
<p align="center" style="align: center;">
|
||||
<a href="https://npm.im/@auth/prisma-adapter">
|
||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||
</a>
|
||||
<a href="https://www.npmtrends.com/next-auth">
|
||||
<img src="https://img.shields.io/npm/dm/next-auth?style=flat-square" alt="Downloads" />
|
||||
</a>
|
||||
<a href="https://github.com/nextauthjs/next-auth/stargazers">
|
||||
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="Github Stars" />
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/next-auth">
|
||||
<img src="https://img.shields.io/github/v/release/nextauthjs/next-auth?label=latest&style=flat-square" alt="Github Stable Release" />
|
||||
</a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
Auth.js is a set of open-source packages that are built on Web Standard APIs for authentication in modern applications with any framework on any platform in any JS runtime.
|
||||
|
||||
See [authjs.dev](https://authjs.dev) for our framework-specific libraries, or check out [next-auth.js.org](https://next-auth.js.org) for `next-auth` (Next.js).
|
||||
|
||||
## Features
|
||||
|
||||
### Flexible and easy to use
|
||||
|
||||
- Designed to work with any OAuth service, it supports 2.0+, OIDC
|
||||
- Built-in support for [many popular sign-in services](https://github.com/nextauthjs/next-auth/tree/main/packages/core/src/providers)
|
||||
- Email/Passwordless authentication
|
||||
- Bring Your Database - or none! - stateless authentication with any backend (Active Directory, LDAP, etc.)
|
||||
- Runtime-agnostic, runs anywhere! (Vercel Edge Functions, Node.js, Serverless, etc.)
|
||||
|
||||
### Own your data
|
||||
|
||||
Auth.js can be used with or without a database.
|
||||
|
||||
- An open-source solution that allows you to keep control of your data
|
||||
- Built-in support for [MySQL, MariaDB, Postgres, Microsoft SQL Server, MongoDB, SQLite, etc.](https://adapters.authjs.dev)
|
||||
- Works great with databases from popular hosting providers
|
||||
|
||||
### Secure by default
|
||||
|
||||
- Promotes the use of passwordless sign-in mechanisms
|
||||
- Designed to be secure by default and encourage best practices for safeguarding user data
|
||||
- Uses Cross-Site Request Forgery (CSRF) Tokens on POST routes (sign in, sign out)
|
||||
- Default cookie policy aims for the most restrictive policy appropriate for each cookie
|
||||
- When JSON Web Tokens are used, they are encrypted by default (JWE) with A256GCM
|
||||
- Features tab/window syncing and session polling to support short-lived sessions
|
||||
- Attempts to implement the latest guidance published by [Open Web Application Security Project](https://owasp.org)
|
||||
|
||||
Advanced configuration allows you to define your routines to handle controlling what accounts are allowed to sign in, for encoding and decoding JSON Web Tokens and to set custom cookie security policies and session properties, so you can control who can sign in and how often sessions have to be re-validated.
|
||||
|
||||
### TypeScript
|
||||
|
||||
Auth.js libraries are written with type safety in mind. [Check out the docs](https://authjs.dev/getting-started/typescript) for more information.
|
||||
|
||||
## Security
|
||||
|
||||
If you think you have found a vulnerability (or are not sure) in Auth.js or any of the related packages (i.e. Adapters), we ask you to read our [Security Policy](https://authjs.dev/security) to reach out responsibly. Please do not open Pull Requests/Issues/Discussions before consulting with us.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
[Auth.js is made possible thanks to all of its contributors.](https://authjs.dev/contributors)
|
||||
|
||||
<a href="https://github.com/nextauthjs/next-auth/graphs/contributors">
|
||||
<img width="500px" src="https://contrib.rocks/image?repo=nextauthjs/next-auth" />
|
||||
</a>
|
||||
<div>
|
||||
<a href="https://vercel.com?utm_source=nextauthjs&utm_campaign=oss"></a>
|
||||
</div>
|
||||
|
||||
### Support
|
||||
|
||||
We have an [OpenCollective](https://opencollective.com/nextauth) for individuals and companies looking to contribute financially to the project!
|
||||
|
||||
<!--sponsors start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://vercel.com" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/14985020?v=4" alt="Vercel Logo" />
|
||||
</a><br />
|
||||
<div>Vercel</div><br />
|
||||
<sub>🥉 Bronze Financial Sponsor <br /> ☁️ Infrastructure Support</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://prisma.io" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/17219288?v=4" alt="Prisma Logo" />
|
||||
</a><br />
|
||||
<div>Prisma</div><br />
|
||||
<sub>🥉 Bronze Financial Sponsor</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://clerk.com" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/49538330?s=200&v=4" alt="Clerk Logo" />
|
||||
</a><br />
|
||||
<div>Clerk</div><br />
|
||||
<sub>🥉 Bronze Financial Sponsor</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://lowdefy.com" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/47087496?s=200&v=4" alt="Lowdefy Logo" />
|
||||
</a><br />
|
||||
<div>Lowdefy</div><br />
|
||||
<sub>🥉 Bronze Financial Sponsor</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://workos.com" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/47638084?s=200&v=4" alt="WorkOS Logo" />
|
||||
</a><br />
|
||||
<div>WorkOS</div><br />
|
||||
<sub>🥉 Bronze Financial Sponsor</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://www.descope.com" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/97479186?v=4" alt="Descope Logo" />
|
||||
</a><br />
|
||||
<div>Descope</div><br />
|
||||
<sub>🥉 Bronze Financial Sponsor</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://checklyhq.com" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/25982255?v=4" alt="Checkly Logo" />
|
||||
</a><br />
|
||||
<div>Checkly</div><br />
|
||||
<sub>☁️ Infrastructure Support</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://superblog.ai/" target="_blank">
|
||||
<img width="128px" src="https://d33wubrfki0l68.cloudfront.net/cdc4a3833bd878933fcc131655878dbf226ac1c5/10cd6/images/logo_bolt_small.png" alt="superblog Logo" />
|
||||
</a><br />
|
||||
<div>superblog</div><br />
|
||||
<sub>☁️ Infrastructure Support</sub>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br />
|
||||
<!--sponsors end-->
|
||||
|
||||
## Contributing
|
||||
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please first read
|
||||
our [Contributing Guide](https://github.com/nextauthjs/.github/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
ISC
|
||||
@@ -13,6 +13,9 @@ AUTH0_ID=
|
||||
AUTH0_SECRET=
|
||||
AUTH0_ISSUER=
|
||||
|
||||
DESCOPE_ID=
|
||||
DESCOPE_SECRET=
|
||||
|
||||
KEYCLOAK_ID=
|
||||
KEYCLOAK_SECRET=
|
||||
KEYCLOAK_ISSUER=
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
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)
|
||||
](https://github.com/nextauthjs/.github/blob/main/CONTRIBUTING.md#setting-up-local-environment)
|
||||
@@ -14,10 +14,10 @@
|
||||
},
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@next-auth/fauna-adapter": "workspace:*",
|
||||
"@next-auth/prisma-adapter": "workspace:*",
|
||||
"@next-auth/supabase-adapter": "workspace:*",
|
||||
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
||||
"@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",
|
||||
|
||||
@@ -37,22 +37,22 @@ import WorkOS from "next-auth/providers/workos"
|
||||
|
||||
// // Prisma
|
||||
// import { PrismaClient } from "@prisma/client"
|
||||
// import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
// 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 "@next-auth/fauna-adapter"
|
||||
// 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 { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
// const adapter = TypeORMLegacyAdapter({
|
||||
// import { TypeORMAdapter } from "@auth/typeorm-adapter"
|
||||
// const adapter = TypeORMAdapter({
|
||||
// type: "sqlite",
|
||||
// name: "next-auth-test-memory",
|
||||
// database: "./typeorm/dev.db",
|
||||
@@ -60,7 +60,7 @@ import WorkOS from "next-auth/providers/workos"
|
||||
// })
|
||||
|
||||
// // Supabase
|
||||
// import { SupabaseAdapter } from "@next-auth/supabase-adapter"
|
||||
// import { SupabaseAdapter } from "@auth/supabase-adapter"
|
||||
// const adapter = SupabaseAdapter({
|
||||
// url: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
||||
@@ -78,45 +78,130 @@ export const authOptions: NextAuthOptions = {
|
||||
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: "" }
|
||||
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 }),
|
||||
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" }),
|
||||
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 }),
|
||||
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 }),
|
||||
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 }),
|
||||
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 }),
|
||||
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 }),
|
||||
Wikimedia({
|
||||
clientId: process.env.WIKIMEDIA_ID,
|
||||
clientSecret: process.env.WIKIMEDIA_SECRET,
|
||||
}),
|
||||
WorkOS({
|
||||
clientId: process.env.WORKOS_ID,
|
||||
clientSecret: process.env.WORKOS_SECRET,
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ BEYOND_IDENTITY_CLIENT_ID=
|
||||
BEYOND_IDENTITY_CLIENT_SECRET=
|
||||
BEYOND_IDENTITY_ISSUER=
|
||||
|
||||
DESCOPE_ID=
|
||||
DESCOPE_SECRET=
|
||||
|
||||
GITHUB_ID=
|
||||
GITHUB_SECRET=
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { handlers } from "auth"
|
||||
export const { GET, POST } = handlers
|
||||
export const runtime = "edge"
|
||||
@@ -1,10 +0,0 @@
|
||||
import { auth } from "auth"
|
||||
import { NextResponse } from "next/server"
|
||||
|
||||
export const GET = auth(function GET(req) {
|
||||
if (req.auth) {
|
||||
return NextResponse.json(req.auth)
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: "Not authenticated" }, { status: 401 })
|
||||
})
|
||||
@@ -1,37 +1,6 @@
|
||||
import { auth } from "auth"
|
||||
import { cookies, headers } from "next/headers"
|
||||
|
||||
function SignIn({ id, children }: any) {
|
||||
const $cookies = cookies()
|
||||
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||
return (
|
||||
<form action={`/api/auth/signin/${id}`} method="post">
|
||||
<button type="submit">{children}</button>
|
||||
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
function SignOut({ children }: any) {
|
||||
const $cookies = cookies()
|
||||
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||
return (
|
||||
<form action="/api/auth/signout" method="post">
|
||||
<button type="submit">{children}</button>
|
||||
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||
</form>
|
||||
)
|
||||
}
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
|
||||
export default async function Page() {
|
||||
const session = await auth(headers())
|
||||
if (session) {
|
||||
return (
|
||||
<>
|
||||
<pre>{JSON.stringify(session, null, 2)}</pre>
|
||||
<SignOut>Sign out</SignOut>
|
||||
</>
|
||||
)
|
||||
}
|
||||
return <SignIn id="github">Sign in with github</SignIn>
|
||||
const session = await unstable_getServerSession()
|
||||
return <pre>{JSON.stringify(session, null, 2)}</pre>
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import { NextAuth } from "next-auth"
|
||||
import GitHub from "@auth/core/providers/github"
|
||||
|
||||
export const { handlers, auth } = NextAuth({
|
||||
providers: [GitHub],
|
||||
callbacks: {
|
||||
async authorized({ request, auth }) {
|
||||
// if (request.method === "POST") {
|
||||
// const [, token] = request.headers.get("Authorization")?.split(" ")
|
||||
// const valid = validateToken(token)
|
||||
// // If the request has a valid auth token, it is authorized
|
||||
// if (valid) return true
|
||||
// return NextResponse.json("Invalid auth token", { status: 401 })
|
||||
// }
|
||||
|
||||
// Logged in users are authorized, otherwise, will redirect to login
|
||||
// You could also return a custom redirect instead of the sign-in page
|
||||
return !!auth
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -1,6 +1,6 @@
|
||||
import Link from "next/link"
|
||||
import styles from "./footer.module.css"
|
||||
import packageJSON from "next-auth/package.json"
|
||||
import packageJSON from "package.json"
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
|
||||
@@ -76,6 +76,12 @@ export default function Header() {
|
||||
<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,10 +1,45 @@
|
||||
// export { auth as default } from "auth"
|
||||
import { auth } from "auth"
|
||||
import { NextResponse } from "next/server"
|
||||
|
||||
export default auth((req) => {
|
||||
if (req.auth) return NextResponse.json(req.auth)
|
||||
return NextResponse.json("Not authorized", { status: 401 })
|
||||
})
|
||||
export { 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,
|
||||
// },
|
||||
// })
|
||||
|
||||
@@ -15,15 +15,14 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*",
|
||||
"next-auth": "workspace:*",
|
||||
"@next-auth/fauna-adapter": "workspace:*",
|
||||
"@next-auth/prisma-adapter": "workspace:*",
|
||||
"@next-auth/supabase-adapter": "workspace:*",
|
||||
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
||||
"@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.2-canary.12",
|
||||
"next": "13.4.0",
|
||||
"next-auth": "workspace:*",
|
||||
"nodemailer": "^6",
|
||||
"react": "^18",
|
||||
|
||||
@@ -2,14 +2,15 @@ import { Auth, type AuthConfig } from "@auth/core"
|
||||
|
||||
// Providers
|
||||
import Apple from "@auth/core/providers/apple"
|
||||
import Asgardeo from "@auth/core/providers/asgardeo"
|
||||
// import Asgardeo from "@auth/core/providers/asgardeo"
|
||||
import Auth0 from "@auth/core/providers/auth0"
|
||||
import AzureAD from "@auth/core/providers/azure-ad"
|
||||
import AzureB2C from "@auth/core/providers/azure-ad-b2c"
|
||||
import BeyondIdentity from "@auth/core/providers/beyondidentity"
|
||||
// import BeyondIdentity from "@auth/core/providers/beyondidentity"
|
||||
import BoxyHQSAML from "@auth/core/providers/boxyhq-saml"
|
||||
// import Cognito from "@auth/core/providers/cognito"
|
||||
import Credentials from "@auth/core/providers/credentials"
|
||||
import Descope from "@auth/core/providers/descope"
|
||||
import Discord from "@auth/core/providers/discord"
|
||||
import DuendeIDS6 from "@auth/core/providers/duende-identity-server6"
|
||||
// import Email from "@auth/core/providers/email"
|
||||
@@ -41,22 +42,22 @@ import WorkOS from "@auth/core/providers/workos"
|
||||
|
||||
// // Prisma
|
||||
// import { PrismaClient } from "@prisma/client"
|
||||
// import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
// 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 "@next-auth/fauna-adapter"
|
||||
// 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 { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
// const adapter = TypeORMLegacyAdapter({
|
||||
// import { TypeORMAdapter } from "@auth/typeorm-adapter"
|
||||
// const adapter = TypeORMAdapter({
|
||||
// type: "sqlite",
|
||||
// name: "next-auth-test-memory",
|
||||
// database: "./typeorm/dev.db",
|
||||
@@ -64,7 +65,7 @@ import WorkOS from "@auth/core/providers/workos"
|
||||
// })
|
||||
|
||||
// // Supabase
|
||||
// import { SupabaseAdapter } from "@next-auth/supabase-adapter"
|
||||
// import { SupabaseAdapter } from "@auth/supabase-adapter"
|
||||
// const adapter = SupabaseAdapter({
|
||||
// url: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
||||
@@ -85,8 +86,8 @@ export const authConfig: AuthConfig = {
|
||||
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 }),
|
||||
Asgardeo({ clientId: process.env.ASGARDEO_CLIENT_ID, clientSecret: process.env.ASGARDEO_CLIENT_SECRET, issuer: process.env.ASGARDEO_ISSUER }),
|
||||
Apple({ clientId: process.env.APPLE_ID, clientSecret: process.env.APPLE_SECRET as string }),
|
||||
// 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 }),
|
||||
AzureAD({
|
||||
clientId: process.env.AZURE_AD_CLIENT_ID,
|
||||
@@ -94,19 +95,20 @@ export const authConfig: AuthConfig = {
|
||||
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 }),
|
||||
BeyondIdentity({
|
||||
clientId: process.env.BEYOND_IDENTITY_CLIENT_ID,
|
||||
clientSecret: process.env.BEYOND_IDENTITY_CLIENT_SECRET,
|
||||
issuer: process.env.BEYOND_IDENTITY_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" }),
|
||||
// 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 }),
|
||||
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, redirectProxy: process.env.AUTH_REDIRECT_PROXY_URL }),
|
||||
GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET, redirectProxyUrl: process.env.AUTH_REDIRECT_PROXY_URL }),
|
||||
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 }),
|
||||
@@ -115,7 +117,7 @@ export const authConfig: AuthConfig = {
|
||||
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 }),
|
||||
Notion({ clientId: process.env.NOTION_ID, clientSecret: process.env.NOTION_SECRET, redirectUri: process.env.NOTION_REDIRECT_URI }),
|
||||
Notion({ clientId: process.env.NOTION_ID, clientSecret: process.env.NOTION_SECRET, redirectUri: process.env.NOTION_REDIRECT_URI as string }),
|
||||
// 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 }),
|
||||
@@ -1,9 +1,9 @@
|
||||
// This is an example of to protect an API route
|
||||
import { authConfig } from "../auth-old/[...nextauth]"
|
||||
import { getServerSession } from "next-auth/next"
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await getServerSession(req, res, authConfig as any)
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
|
||||
if (session) {
|
||||
res.send({
|
||||
8
apps/dev/nextjs/pages/api/examples/session.js
Normal file
8
apps/dev/nextjs/pages/api/examples/session.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// This is an example of how to access a session from an API route
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
res.json(session)
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { authConfig } from "../auth-old/[...nextauth]"
|
||||
// This is an example of how to access a session from an API route
|
||||
import { getServerSession } from "next-auth/next"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await getServerSession(req, res, authConfig as any)
|
||||
res.json(session)
|
||||
}
|
||||
30
apps/dev/nextjs/pages/api/examples/supabase-rls.js
Normal file
30
apps/dev/nextjs/pages/api/examples/supabase-rls.js
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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 { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
import { createClient } from "@supabase/supabase-js"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await unstable_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,6 +1,6 @@
|
||||
// This is an example of how to protect content using server rendering
|
||||
import { getServerSession } from "next-auth/next"
|
||||
import { authConfig } from "./api/auth-old/[...nextauth]"
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
import Layout from "../components/layout"
|
||||
import AccessDenied from "../components/access-denied"
|
||||
|
||||
@@ -26,7 +26,11 @@ export default function Page({ content, session }) {
|
||||
}
|
||||
|
||||
export async function getServerSideProps(context) {
|
||||
const session = await getServerSession(context.req, context.res, authConfig)
|
||||
const session = await unstable_getServerSession(
|
||||
context.req,
|
||||
context.res,
|
||||
authOptions
|
||||
)
|
||||
let content = null
|
||||
|
||||
if (session) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getServerSession } from "next-auth/next"
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import Layout from "../components/layout"
|
||||
import { authConfig } from "./api/auth-old/[...nextauth]"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
|
||||
export default function Page() {
|
||||
// As this page uses Server Side Rendering, the `session` will be already
|
||||
@@ -12,11 +12,11 @@ export default function Page() {
|
||||
<Layout>
|
||||
<h1>Server Side Rendering</h1>
|
||||
<p>
|
||||
This page uses the <strong>getServerSession()</strong> method in{" "}
|
||||
<strong>getServerSideProps()</strong>.
|
||||
This page uses the <strong>unstable_getServerSession()</strong> method
|
||||
in <strong>getServerSideProps()</strong>.
|
||||
</p>
|
||||
<p>
|
||||
Using <strong>getServerSession()</strong> in{" "}
|
||||
Using <strong>unstable_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.
|
||||
@@ -40,7 +40,11 @@ export default function Page() {
|
||||
export async function getServerSideProps(context) {
|
||||
return {
|
||||
props: {
|
||||
session: await getServerSession(context.req, context.res, authConfig),
|
||||
session: await unstable_getServerSession(
|
||||
context.req,
|
||||
context.res,
|
||||
authOptions
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
48
apps/dev/nextjs/pages/supabase-client-rls.js
Normal file
48
apps/dev/nextjs/pages/supabase-client-rls.js
Normal file
@@ -0,0 +1,48 @@
|
||||
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) {
|
||||
// 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>
|
||||
)
|
||||
}
|
||||
68
apps/dev/nextjs/pages/supabase-ssr.js
Normal file
68
apps/dev/nextjs/pages/supabase-ssr.js
Normal file
@@ -0,0 +1,68 @@
|
||||
// This is an example of how to protect content using server rendering
|
||||
// and fetching data from Supabase with RLS enabled.
|
||||
import { unstable_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 unstable_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,
|
||||
},
|
||||
}
|
||||
}
|
||||
9
apps/dev/nextjs/types/nextauth.d.ts
vendored
9
apps/dev/nextjs/types/nextauth.d.ts
vendored
@@ -18,12 +18,3 @@ declare module "next-auth" {
|
||||
foo: string
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
[key: string]: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
"svelte": "3.55.0",
|
||||
"svelte-check": "2.10.2",
|
||||
"typescript": "4.9.4",
|
||||
"vite": "4.0.1"
|
||||
"vite": "4.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*",
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
/** @type {import("next").NextConfig} */
|
||||
module.exports = {
|
||||
reactStrictMode: true,
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
NEXTAUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.vercel.app/32
|
||||
NEXTAUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32
|
||||
|
||||
|
||||
AUTH0_ID=
|
||||
AUTH0_SECRET=
|
||||
AUTH0_ISSUER=
|
||||
|
||||
DESCOPE_ID=
|
||||
DESCOPE_SECRET=
|
||||
|
||||
FACEBOOK_ID=
|
||||
FACEBOOK_SECRET=
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<a href="https://nextjs.org" target="_blank">
|
||||
<img height="64" src="https://nextjs.org/static/favicon/android-chrome-192x192.png" />
|
||||
</a>
|
||||
<h3 align="center"><b>next-auth</b> - Example App</h3>
|
||||
<h3 align="center"><b>NextAuth.js</b> - Example App</h3>
|
||||
<p align="center">
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
@@ -36,7 +36,7 @@ This is an example application that shows how `next-auth` is applied to a basic
|
||||
|
||||
The deployed version can be found at [`next-auth-example.vercel.app`](https://next-auth-example.vercel.app)
|
||||
|
||||
Go to [authjs.dev](https://authjs.dev) for more information and documentation.
|
||||
Go to [next-auth.js.org](https://next-auth.js.org) for more information and documentation.
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -66,7 +66,7 @@ You **can** skip configuring a database and come back to it later if you want.
|
||||
|
||||
For more information about setting up a database, please check out the following links:
|
||||
|
||||
- Docs: [authjs.dev/reference/adapters](https://authjs.dev/reference/adapters)
|
||||
- Docs: [next-auth.js.org/adapters/overview](https://next-auth.js.org/adapters/overview)
|
||||
|
||||
### 3. Configure Authentication Providers
|
||||
|
||||
@@ -76,7 +76,7 @@ For more information about setting up a database, please check out the following
|
||||
|
||||
e.g. For Google OAuth you would use: `http://localhost:3000/api/auth/callback/google`
|
||||
|
||||
A list of configured providers and their callback URLs is available from the endpoint `/api/auth/providers`. You can find more information at [authjs.dev/getting-started/oauth-tutorial](https://authjs.dev/getting-started/oauth-tutorial)
|
||||
A list of configured providers and their callback URLs is available from the endpoint `/api/auth/providers`. You can find more information at https://next-auth.js.org/configuration/providers/oauth
|
||||
|
||||
3. You can also choose to specify an SMTP server for passwordless sign in via email.
|
||||
|
||||
@@ -106,4 +106,4 @@ Follow the [Deployment documentation](https://authjs.dev/guides/basics/deploymen
|
||||
<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>
|
||||
<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,3 +0,0 @@
|
||||
import { handlers } from "auth"
|
||||
export const { GET, POST } = handlers
|
||||
export const runtime = "edge"
|
||||
@@ -1,10 +0,0 @@
|
||||
import { auth } from "auth"
|
||||
import { NextResponse } from "next/server"
|
||||
|
||||
export const GET = auth(function GET(req) {
|
||||
if (req.auth) {
|
||||
return NextResponse.json(req.auth)
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: "Not authenticated" }, { status: 401 })
|
||||
})
|
||||
@@ -1,24 +0,0 @@
|
||||
import Header from "components/header"
|
||||
import Footer from "components/footer"
|
||||
import './styles.css'
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<Header />
|
||||
<main>
|
||||
{children}
|
||||
</main>
|
||||
<Footer />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
||||
export const runtime = "experimental-edge"
|
||||
@@ -1,13 +0,0 @@
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<h1>NextAuth.js Example</h1>
|
||||
<p>
|
||||
This is an example site to demonstrate how to use{" "}
|
||||
<a href="https://authjs.dev">NextAuth.js</a> for authentication.
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const runtime = "experimental-edge"
|
||||
@@ -1,39 +0,0 @@
|
||||
import { auth } from "auth"
|
||||
import { cookies, headers } from "next/headers"
|
||||
|
||||
function SignIn({ id, children, className }: any) {
|
||||
const $cookies = cookies()
|
||||
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||
return (
|
||||
<form action={`/api/auth/signin/${id}`} method="post">
|
||||
<button className={className} type="submit">{children}</button>
|
||||
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
function SignOut({ children }: any) {
|
||||
const $cookies = cookies()
|
||||
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||
return (
|
||||
<form action="/api/auth/signout" method="post">
|
||||
<button type="submit">{children}</button>
|
||||
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
export default async function Page() {
|
||||
const session = await auth(headers())
|
||||
if (session) {
|
||||
return (
|
||||
<>
|
||||
<pre>{JSON.stringify(session, null, 2)}</pre>
|
||||
<SignOut>Sign out</SignOut>
|
||||
</>
|
||||
)
|
||||
}
|
||||
return <SignIn id="github">Sign in with github</SignIn>
|
||||
}
|
||||
|
||||
export const runtime = "experimental-edge"
|
||||
@@ -1,21 +0,0 @@
|
||||
import NextAuth from "next-auth"
|
||||
import GitHub from "@auth/core/providers/github"
|
||||
|
||||
export const { handlers, auth } = NextAuth({
|
||||
providers: [GitHub],
|
||||
callbacks: {
|
||||
async authorized({ request, auth }) {
|
||||
// if (request.method === "POST") {
|
||||
// const [, token] = request.headers.get("Authorization")?.split(" ")
|
||||
// const valid = validateToken(token)
|
||||
// // If the request has a valid auth token, it is authorized
|
||||
// if (valid) return true
|
||||
// return NextResponse.json("Invalid auth token", { status: 401 })
|
||||
// }
|
||||
|
||||
// Logged in users are authorized, otherwise, will redirect to login
|
||||
// You could also return a custom redirect instead of the sign-in page
|
||||
return !!auth
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -1,6 +1,6 @@
|
||||
import Link from "next/link"
|
||||
import styles from "./footer.module.css"
|
||||
import packageJSON from "next-auth/package.json"
|
||||
import packageJSON from "../package.json"
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
@@ -8,10 +8,10 @@ export default function Footer() {
|
||||
<hr />
|
||||
<ul className={styles.navItems}>
|
||||
<li className={styles.navItem}>
|
||||
<a href="https://authjs.dev">Documentation</a>
|
||||
<a href="https://next-auth.js.org">Documentation</a>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<a href="https://www.npmjs.com/package/@auth/core">NPM</a>
|
||||
<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>
|
||||
@@ -20,7 +20,7 @@ export default function Footer() {
|
||||
<Link href="/policy">Policy</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<em>{packageJSON.version}</em>
|
||||
<em>next-auth@{packageJSON.dependencies["next-auth"]}</em>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* Set min-height to avoid page reflow while session loading */
|
||||
.signedInStatus {
|
||||
position: relative;
|
||||
display: block;
|
||||
min-height: 4rem;
|
||||
width: 100%;
|
||||
|
||||
@@ -1,63 +1,65 @@
|
||||
import Link from "next/link"
|
||||
import { auth } from "auth"
|
||||
import { cookies, headers } from "next/headers"
|
||||
import { signIn, signOut, useSession } from "next-auth/react"
|
||||
import styles from "./header.module.css"
|
||||
|
||||
function SignIn({ id, children, className }: any) {
|
||||
const $cookies = cookies()
|
||||
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||
return (
|
||||
<form action={`/api/auth/signin/${id}`} method="post">
|
||||
<button className={className} type="submit">{children}</button>
|
||||
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
function SignOut({ children, className }: any) {
|
||||
const $cookies = cookies()
|
||||
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||
return (
|
||||
<form action="/api/auth/signout" method="post">
|
||||
<button className={className} type="submit">{children}</button>
|
||||
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
// The approach used in this component shows how to built a sign in and sign out
|
||||
// The approach used in this component shows how to build 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 async function Header() {
|
||||
const session = await auth(headers())
|
||||
export default function Header() {
|
||||
const { data: session, status } = useSession()
|
||||
const loading = status === "loading"
|
||||
|
||||
return (
|
||||
<header>
|
||||
<noscript>
|
||||
<style>{".nojs-show { opacity: 1; top: 0; }"}</style>
|
||||
<style>{`.nojs-show { opacity: 1; top: 0; }`}</style>
|
||||
</noscript>
|
||||
<div className={styles.signedInStatus}>
|
||||
<p className={`nojs-show ${styles.loaded}`}>
|
||||
<p
|
||||
className={`nojs-show ${
|
||||
!session && loading ? styles.loading : styles.loaded
|
||||
}`}
|
||||
>
|
||||
{!session && (
|
||||
<>
|
||||
<span className={styles.notSignedInText}>
|
||||
You are not signed in
|
||||
</span>
|
||||
<SignIn className={styles.buttonPrimary}>Sign In</SignIn>
|
||||
<a
|
||||
href={`/api/auth/signin`}
|
||||
className={styles.buttonPrimary}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
signIn()
|
||||
}}
|
||||
>
|
||||
Sign in
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
{session && (
|
||||
{session?.user && (
|
||||
<>
|
||||
{session.user.image && (
|
||||
<img src={session.user.image} className={styles.avatar} />
|
||||
<span
|
||||
style={{ backgroundImage: `url('${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}
|
||||
<strong>{session.user.email ?? session.user.name}</strong>
|
||||
</span>
|
||||
<SignOut className={styles.button}>Sign Out</SignOut>
|
||||
<a
|
||||
href={`/api/auth/signout`}
|
||||
className={styles.button}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
signOut()
|
||||
}}
|
||||
>
|
||||
Sign out
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
@@ -71,7 +73,7 @@ export default async function Header() {
|
||||
<Link href="/client">Client</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/server-component">Server</Link>
|
||||
<Link href="/server">Server</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/protected">Protected</Link>
|
||||
@@ -80,12 +82,13 @@ export default async function Header() {
|
||||
<Link href="/api-example">API</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/middleware-protected">Middleware protected</Link>
|
||||
<Link href="/admin">Admin</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/me">Me</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
||||
export const runtime = "experimental-edge"
|
||||
|
||||
13
apps/examples/nextjs/components/layout.tsx
Normal file
13
apps/examples/nextjs/components/layout.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import Header from "./header"
|
||||
import Footer from "./footer"
|
||||
import type { ReactNode } from "react"
|
||||
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main>{children}</main>
|
||||
<Footer />
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,10 +1,17 @@
|
||||
// export { auth as default } from "auth"
|
||||
import { auth } from "auth"
|
||||
import { NextResponse } from "next/server"
|
||||
import { withAuth } from "next-auth/middleware"
|
||||
|
||||
export default auth((req) => {
|
||||
if (req.auth) return NextResponse.json(req.auth)
|
||||
return NextResponse.json("Not authorized", { status: 401 })
|
||||
// More on how NextAuth.js middleware works: https://next-auth.js.org/configuration/nextjs#middleware
|
||||
export default withAuth({
|
||||
callbacks: {
|
||||
authorized({ req, token }) {
|
||||
// `/admin` requires admin role
|
||||
if (req.nextUrl.pathname === "/admin") {
|
||||
return token?.userRole === "admin"
|
||||
}
|
||||
// `/me` only requires the user to be logged in
|
||||
return !!token
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const config = { matcher: ["/middleware-protected"] }
|
||||
export const config = { matcher: ["/admin", "/me"] }
|
||||
|
||||
10
apps/examples/nextjs/next-auth.d.ts
vendored
Normal file
10
apps/examples/nextjs/next-auth.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import "next-auth/jwt"
|
||||
|
||||
// Read more at: https://next-auth.js.org/getting-started/typescript#module-augmentation
|
||||
|
||||
declare module "next-auth/jwt" {
|
||||
interface JWT {
|
||||
/** The user's role. */
|
||||
userRole?: "admin"
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,4 @@
|
||||
/** @type {import("next").NextConfig} */
|
||||
module.exports = {
|
||||
webpack(config) {
|
||||
config.experiments = { ...config.experiments, topLevelAwait: true }
|
||||
return config
|
||||
},
|
||||
experimental: { appDir: true },
|
||||
typescript: { ignoreBuildErrors: true },
|
||||
reactStrictMode: true,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "nextjs-example-app",
|
||||
"description": "An example project for NextAuth.js with Next.js",
|
||||
"repository": "https://github.com/nextauthjs/next-auth-example.git",
|
||||
"bugs": {
|
||||
@@ -19,9 +18,8 @@
|
||||
"Lluis Agusti <hi@llu.lu>"
|
||||
],
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*",
|
||||
"next": "latest",
|
||||
"next-auth": "workspace:*",
|
||||
"next-auth": "latest",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
|
||||
18
apps/examples/nextjs/pages/_app.tsx
Normal file
18
apps/examples/nextjs/pages/_app.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { SessionProvider } from "next-auth/react"
|
||||
import "./styles.css"
|
||||
|
||||
import type { AppProps } from "next/app"
|
||||
import type { Session } from "next-auth"
|
||||
|
||||
// Use of the <SessionProvider> is mandatory to allow components that call
|
||||
// `useSession()` anywhere in your application to access the `session` object.
|
||||
export default function App({
|
||||
Component,
|
||||
pageProps: { session, ...pageProps },
|
||||
}: AppProps<{ session: Session }>) {
|
||||
return (
|
||||
<SessionProvider session={session}>
|
||||
<Component {...pageProps} />
|
||||
</SessionProvider>
|
||||
)
|
||||
}
|
||||
17
apps/examples/nextjs/pages/admin.tsx
Normal file
17
apps/examples/nextjs/pages/admin.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<Layout>
|
||||
<h1>This page is protected by Middleware</h1>
|
||||
<p>Only admin users can see this page.</p>
|
||||
<p>
|
||||
To learn more about the NextAuth middleware see
|
||||
<a href="https://next-auth.js.org/configuration/nextjs#middleware">
|
||||
the docs
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
19
apps/examples/nextjs/pages/api-example.tsx
Normal file
19
apps/examples/nextjs/pages/api-example.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function ApiExamplePage() {
|
||||
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>
|
||||
)
|
||||
}
|
||||
44
apps/examples/nextjs/pages/api/auth/[...nextauth].ts
Normal file
44
apps/examples/nextjs/pages/api/auth/[...nextauth].ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import NextAuth, { NextAuthOptions } from "next-auth"
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
import FacebookProvider from "next-auth/providers/facebook"
|
||||
import GithubProvider from "next-auth/providers/github"
|
||||
import TwitterProvider from "next-auth/providers/twitter"
|
||||
import Auth0Provider from "next-auth/providers/auth0"
|
||||
|
||||
// For more information on each option (and a full list of options) go to
|
||||
// https://next-auth.js.org/configuration/options
|
||||
export const authOptions: NextAuthOptions = {
|
||||
// https://next-auth.js.org/configuration/providers/oauth
|
||||
providers: [
|
||||
Auth0Provider({
|
||||
clientId: process.env.AUTH0_ID,
|
||||
clientSecret: process.env.AUTH0_SECRET,
|
||||
issuer: process.env.AUTH0_ISSUER,
|
||||
}),
|
||||
FacebookProvider({
|
||||
clientId: process.env.FACEBOOK_ID,
|
||||
clientSecret: process.env.FACEBOOK_SECRET,
|
||||
}),
|
||||
GithubProvider({
|
||||
clientId: process.env.GITHUB_ID,
|
||||
clientSecret: process.env.GITHUB_SECRET,
|
||||
}),
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_ID,
|
||||
clientSecret: process.env.GOOGLE_SECRET,
|
||||
}),
|
||||
TwitterProvider({
|
||||
clientId: process.env.TWITTER_ID,
|
||||
clientSecret: process.env.TWITTER_SECRET,
|
||||
version: "2.0",
|
||||
}),
|
||||
],
|
||||
callbacks: {
|
||||
async jwt({ token }) {
|
||||
token.userRole = "admin"
|
||||
return token
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default NextAuth(authOptions)
|
||||
14
apps/examples/nextjs/pages/api/examples/jwt.ts
Normal file
14
apps/examples/nextjs/pages/api/examples/jwt.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
// This is an example of how to read a JSON Web Token from an API route
|
||||
import { getToken } from "next-auth/jwt"
|
||||
|
||||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
// If you don't have the NEXTAUTH_SECRET environment variable set,
|
||||
// you will have to pass your secret as `secret` to `getToken`
|
||||
const token = await getToken({ req })
|
||||
res.send(JSON.stringify(token, null, 2))
|
||||
}
|
||||
23
apps/examples/nextjs/pages/api/examples/protected.ts
Normal file
23
apps/examples/nextjs/pages/api/examples/protected.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// This is an example of to protect an API route
|
||||
import { getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
|
||||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const session = await getServerSession(req, res, authOptions)
|
||||
|
||||
if (session) {
|
||||
return res.send({
|
||||
content:
|
||||
"This is protected content. You can access this content because you are signed in.",
|
||||
})
|
||||
}
|
||||
|
||||
res.send({
|
||||
error: "You must be signed in to view the protected content on this page.",
|
||||
})
|
||||
}
|
||||
13
apps/examples/nextjs/pages/api/examples/session.ts
Normal file
13
apps/examples/nextjs/pages/api/examples/session.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
// This is an example of how to access a session from an API route
|
||||
import { getServerSession } from "next-auth"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
|
||||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const session = await getServerSession(req, res, authOptions)
|
||||
res.send(JSON.stringify(session, null, 2))
|
||||
}
|
||||
@@ -1,13 +1,15 @@
|
||||
export default function Page() {
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function ClientPage() {
|
||||
return (
|
||||
<>
|
||||
<Layout>
|
||||
<h1>Client Side Rendering</h1>
|
||||
<p>
|
||||
This page uses the <strong>useSession()</strong> React Hook in the{" "}
|
||||
<strong></Header></strong> component.
|
||||
<strong><Header/></strong> component.
|
||||
</p>
|
||||
<p>
|
||||
The <strong>useSession()</strong> React Hook easy to use and allows
|
||||
The <strong>useSession()</strong> React Hook is easy to use and allows
|
||||
pages to render very quickly.
|
||||
</p>
|
||||
<p>
|
||||
@@ -20,6 +22,6 @@ export default function Page() {
|
||||
The disadvantage of <strong>useSession()</strong> is that it requires
|
||||
client side JavaScript.
|
||||
</p>
|
||||
</>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
13
apps/examples/nextjs/pages/index.tsx
Normal file
13
apps/examples/nextjs/pages/index.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function IndexPage() {
|
||||
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>
|
||||
)
|
||||
}
|
||||
12
apps/examples/nextjs/pages/me.tsx
Normal file
12
apps/examples/nextjs/pages/me.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import { useSession } from "next-auth/react"
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function MePage() {
|
||||
const { data } = useSession()
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
32
apps/examples/nextjs/pages/policy.tsx
Normal file
32
apps/examples/nextjs/pages/policy.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function PolicyPage() {
|
||||
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>
|
||||
)
|
||||
}
|
||||
40
apps/examples/nextjs/pages/protected.tsx
Normal file
40
apps/examples/nextjs/pages/protected.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { useState, useEffect } from "react"
|
||||
import { useSession } from "next-auth/react"
|
||||
import Layout from "../components/layout"
|
||||
import AccessDenied from "../components/access-denied"
|
||||
|
||||
export default function ProtectedPage() {
|
||||
const { data: session } = useSession()
|
||||
const [content, setContent] = useState()
|
||||
|
||||
// Fetch content from protected route
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const res = await fetch("/api/examples/protected")
|
||||
const json = await res.json()
|
||||
if (json.content) {
|
||||
setContent(json.content)
|
||||
}
|
||||
}
|
||||
fetchData()
|
||||
}, [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 ?? "\u00a0"}</strong>
|
||||
</p>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
44
apps/examples/nextjs/pages/server.tsx
Normal file
44
apps/examples/nextjs/pages/server.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
import Layout from "../components/layout"
|
||||
|
||||
import type { GetServerSidePropsContext } from "next"
|
||||
import { useSession } from "next-auth/react"
|
||||
|
||||
export default function ServerSidePage() {
|
||||
const { data: session } = useSession()
|
||||
// As this page uses Server Side Rendering, the `session` will be already
|
||||
// populated on render without needing to go through a loading stage.
|
||||
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 the recommended approach if you
|
||||
need to support Server Side Rendering with authentication.
|
||||
</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>
|
||||
<pre>{JSON.stringify(session, null, 2)}</pre>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
// Export the `session` prop to use sessions with Server Side Rendering
|
||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
return {
|
||||
props: {
|
||||
session: await getServerSession(context.req, context.res, authOptions),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
body {
|
||||
color: red;
|
||||
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";
|
||||
@@ -7,7 +6,7 @@ body {
|
||||
max-width: 680px;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
color: var(--color-text);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
li,
|
||||
2
apps/examples/nextjs/process.d.ts
vendored
2
apps/examples/nextjs/process.d.ts
vendored
@@ -12,5 +12,7 @@ declare namespace NodeJS {
|
||||
GOOGLE_SECRET: string
|
||||
AUTH0_ID: string
|
||||
AUTH0_SECRET: string
|
||||
DESCOPE_ID: string
|
||||
DESCOPE_SECRET: string
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
@@ -16,24 +12,15 @@
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"incremental": true,
|
||||
"jsx": "preserve",
|
||||
"baseUrl": ".",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"strictNullChecks": true
|
||||
"incremental": true
|
||||
},
|
||||
"include": [
|
||||
"process.d.ts",
|
||||
"next-env.d.ts",
|
||||
"next-auth.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts"
|
||||
"**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"jest.config.js"
|
||||
]
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Session } from "@auth/core"
|
||||
import { Session } from "@auth/core/types"
|
||||
|
||||
export default function useSession() {
|
||||
return useState<Session | null>("session", () => null)
|
||||
|
||||
@@ -43,7 +43,7 @@ export async function signIn<
|
||||
|
||||
// TODO: Handle custom base path
|
||||
// TODO: Remove this since Sveltekit offers the CSRF protection via origin check
|
||||
const { csrfToken } = await $fetch("/api/auth/csrf")
|
||||
const { csrfToken } = await $fetch<{ csrfToken: string }>("/api/auth/csrf")
|
||||
|
||||
console.log(_signInUrl)
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { AuthHandler, AuthOptions, Session } from "@auth/core"
|
||||
import { AuthConfig, Session } from "@auth/core/types"
|
||||
import { Auth } from "@auth/core"
|
||||
import { fromNodeMiddleware, H3Event } from "h3"
|
||||
import getURL from "requrl"
|
||||
import { createMiddleware } from "@hattip/adapter-node"
|
||||
|
||||
export function NuxtAuthHandler(options: AuthOptions) {
|
||||
export function NuxtAuthHandler(options: AuthConfig) {
|
||||
async function handler(ctx: { request: Request }) {
|
||||
options.trustHost ??= true
|
||||
|
||||
return AuthHandler(ctx.request, options)
|
||||
return Auth(ctx.request, options)
|
||||
}
|
||||
|
||||
const middleware = createMiddleware(handler)
|
||||
@@ -17,7 +18,7 @@ export function NuxtAuthHandler(options: AuthOptions) {
|
||||
|
||||
export async function getSession(
|
||||
event: H3Event,
|
||||
options: AuthOptions
|
||||
options: AuthConfig
|
||||
): Promise<Session | null> {
|
||||
options.trustHost ??= true
|
||||
|
||||
@@ -30,7 +31,7 @@ export async function getSession(
|
||||
nodeHeaders.append(key, headers[key] as any)
|
||||
})
|
||||
|
||||
const response = await AuthHandler(
|
||||
const response = await Auth(
|
||||
new Request(url, { headers: nodeHeaders }),
|
||||
options
|
||||
)
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
{
|
||||
"name": "playground-nuxt",
|
||||
"name": "next-auth-nuxt",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "nuxt prepare && nuxt build",
|
||||
"dev": "nuxt prepare && export NODE_OPTIONS='--no-experimental-fetch' && nuxt dev",
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt prepare && nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/eslint-config": "^0.1.1",
|
||||
"eslint": "^8.29.0",
|
||||
"h3": "1.0.2",
|
||||
"nuxt": "3.0.0"
|
||||
"h3": "1.6.6",
|
||||
"nuxt": "3.5.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*",
|
||||
"@hattip/adapter-node": "^0.0.22",
|
||||
"@hattip/adapter-node": "^0.0.34",
|
||||
"requrl": "^3.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Session } from "@auth/core"
|
||||
import { Session } from "@auth/core/types"
|
||||
|
||||
export default defineNuxtPlugin(async () => {
|
||||
const session = useSession()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { NuxtAuthHandler } from "@/lib/auth/server"
|
||||
import GithubProvider from "@auth/core/providers/github"
|
||||
import type { AuthOptions } from "@auth/core"
|
||||
import type { AuthConfig } from "@auth/core"
|
||||
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
|
||||
export const authOptions: AuthOptions = {
|
||||
export const authOptions = {
|
||||
secret: runtimeConfig.secret,
|
||||
providers: [
|
||||
GithubProvider({
|
||||
@@ -12,6 +12,6 @@ export const authOptions: AuthOptions = {
|
||||
clientSecret: runtimeConfig.github.clientSecret,
|
||||
}),
|
||||
],
|
||||
}
|
||||
} as AuthConfig
|
||||
|
||||
export default NuxtAuthHandler(authOptions)
|
||||
|
||||
@@ -37,22 +37,31 @@ This documentation site is based on the [Docusaurus](https://docusaurus.io) fram
|
||||
|
||||
To start a local environment of this project, please do the following.
|
||||
|
||||
1. Clone the repository.
|
||||
1. Clone the repo:
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/nextauthjs/docs.git
|
||||
```sh
|
||||
git clone git@github.com:nextauthjs/next-auth.git
|
||||
cd next-auth
|
||||
```
|
||||
|
||||
2. Install dependencies
|
||||
2. Set up the correct pnpm version, using [Corepack](https://nodejs.org/api/corepack.html). Run the following in the project'a root:
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
```sh
|
||||
corepack enable pnpm
|
||||
```
|
||||
|
||||
3. Start the development server
|
||||
(Now, if you run `pnpm --version`, it should print the same verion as the `packageManager` property in the [`package.json` file](https://github.com/nextauthjs/next-auth/blob/main/package.json))
|
||||
|
||||
3. Install packages. Developing requires Node.js v18:
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
```
|
||||
|
||||
4. Start the development server
|
||||
|
||||
```bash
|
||||
$ npm start
|
||||
$ pnpm dev:docs
|
||||
```
|
||||
|
||||
And thats all! Now you should have a local copy of this docs site running at [localhost:3000](http://localhost:3000)!
|
||||
|
||||
@@ -34,7 +34,7 @@ npm install -D nodemailer
|
||||
|
||||
## 2. Setting up a SMTP service
|
||||
|
||||
Next we need a [SMTP service](https://sendgrid.com/blog/what-is-an-smtp-server/) which will be in charge of sending emails from our application. There's a number of services available for this, however [here are the ones](http://nodemailer.com/smtp/well-known/) known to work with `nodemailer`.
|
||||
Next we need a [SMTP service](https://sendgrid.com/blog/what-is-an-smtp-server/) which will be in charge of sending emails from our application. There's a number of services available for this, however [here are the ones](https://community.nodemailer.com/2-0-0-beta/setup-smtp/well-known-services) known to work with `nodemailer`.
|
||||
|
||||
:::info
|
||||
For this tutorial, we're going to be using [Sendgrid](https://sendgrid.com/), but any of the services linked above should work the same
|
||||
@@ -91,12 +91,12 @@ Finally, we'll need to set up a database adapter to store verification tokens th
|
||||
|
||||
An **Adapter** in Auth.js connects your application to whatever database or backend system you want to use to store data for users, their accounts, sessions, etc...
|
||||
|
||||
For this tutorial, we're going to use the **MongoDB** adapter, other any of the other adapters will work just fine.
|
||||
For this tutorial, we're going to use the **MongoDB** adapter, but any of the other adapters will work just fine.
|
||||
|
||||
First, let's start by installing the adapter package:
|
||||
|
||||
```bash npm2yarn2pnpm
|
||||
npm install -D @next-auth/mongodb-adapter mongodb
|
||||
npm install -D @auth/mongodb-adapter mongodb
|
||||
```
|
||||
|
||||
and create a simple MongoDB client:
|
||||
@@ -142,7 +142,7 @@ And now let's reference this new adapter from our Auth.js configuration file:
|
||||
```diff title="pages/api/auth/[...nextauth].ts"
|
||||
import NextAuth from "next-auth"
|
||||
import EmailProvider from "next-auth/providers/email"
|
||||
+ import { MongoDBAdapter } from "@next-auth/mongodb-adapter"
|
||||
+ import { MongoDBAdapter } from "@auth/mongodb-adapter"
|
||||
+ import clientPromise from "../../../lib/mongodb/client"
|
||||
|
||||
export default NextAuth({
|
||||
|
||||
@@ -36,6 +36,10 @@ This tutorial assumes you have a Next.js application set up. If you don't, you c
|
||||
npm install next-auth
|
||||
```
|
||||
|
||||
:::info
|
||||
We are working on a new `@auth/nextjs` package that will make it easier to set up Auth.js with Next.js. Stay tuned! For now, you can use the `next-auth` package.
|
||||
:::
|
||||
|
||||
### Creating the server config
|
||||
|
||||
Create the following [API route](https://nextjs.org/docs/api-routes/dynamic-api-routes#catch-all-api-routes) file. This route contains the necessary configuration for NextAuth.js, as well as the dynamic route handler:
|
||||
@@ -96,11 +100,12 @@ NextAuth.js provides [`useSession()`](/reference/react/#usesession) - a [React H
|
||||
|
||||
```ts title="pages/_app.tsx"
|
||||
import { SessionProvider } from "next-auth/react"
|
||||
import type { AppProps } from 'next/app'
|
||||
|
||||
export default function App({
|
||||
Component,
|
||||
pageProps: { session, ...pageProps },
|
||||
}) {
|
||||
}: AppProps) {
|
||||
return (
|
||||
<SessionProvider session={session}>
|
||||
<Component {...pageProps} />
|
||||
@@ -239,10 +244,13 @@ http://localhost:5173/auth/callback/github
|
||||
TODO Core
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::info
|
||||
The last part of the URL, `[provider]`, is the ID of the provider you're using. In this case, we're using GitHub, so it's `github`. If you're using Google, it'll be `google`, etc... We keep track of the provider IDs internally.
|
||||
|
||||
The same id is used in the `signIn()` method we saw earlier.
|
||||
:::
|
||||
|
||||
To register, tap on "Register application" button.
|
||||
|
||||
The next screen shows all the configurations for your newly created OAuth app. For now, we need two things from it - the **Client ID** and **Client Secret**:
|
||||
@@ -266,7 +274,7 @@ Note that, for each provider, the configuration process will be similar to what
|
||||
2. Create create your OAuth application within it
|
||||
3. Set the callback URL
|
||||
4. Get the Client ID and Generate a Client Secret
|
||||
:::
|
||||
:::
|
||||
|
||||
## 3. Wiring all together
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Using a database adapter
|
||||
---
|
||||
|
||||
An **Adapter** in Auth.js connects your application to whatever database or backend system you want to use to store data for users, their accounts, sessions, etc. Adapters are optional, unless you need to persist user information in your own database, or you want to implement certain flows. The [Email Provider](/getting-started/email-tutorial) requires an adapter to be able to save [Verification Tokens](/reference/adapters/models#verification-token).
|
||||
An **Adapter** in Auth.js connects your application to whatever database or backend system you want to use to store data for users, their accounts, sessions, etc. Adapters are optional, unless you need to persist user information in your own database, or you want to implement certain flows. The [Email Provider](/getting-started/email-tutorial) requires an adapter to be able to save [Verification Tokens](/reference/adapters#verification-token).
|
||||
|
||||
:::tip
|
||||
When using a database, you can still use JWT for session handling for fast access. See the [`session.strategy`](/reference/configuration/auth-config#session) option. Read about the trade-offs of JWT in the [FAQ](/concepts/faq#json-web-tokens).
|
||||
|
||||
@@ -34,7 +34,7 @@ Most OAuth providers cannot be configured with multiple callback URLs or using a
|
||||
|
||||
However, Auth.js **supports Preview deployments**, even **with OAuth providers**:
|
||||
|
||||
1. Determine a stable deployment URL. Eg.: A deployment whose URL does not change between builds, for example. `auth.yourdomain.com`),
|
||||
1. Determine a stable deployment URL. Eg.: A deployment whose URL does not change between builds, for example. `auth.yourdomain.com` (using a subdomain is not a requirement, this can simply be the main site's URL too.),
|
||||
2. Set `AUTH_REDIRECT_PROXY_URL` to that URL, adding the path up until your `[...nextauth]` route. Eg.: (`https://auth.yourdomain.com/api/auth`)
|
||||
3. For your OAuth provider, set the callback URL using the stable deployment URL. Eg.: For GitHub `https://auth.yourdomain.com/api/auth/callback/github`)
|
||||
|
||||
@@ -42,6 +42,9 @@ However, Auth.js **supports Preview deployments**, even **with OAuth providers**
|
||||
To support preview deployments, the `AUTH_SECRET` value needs to be the same for the stable deployment and deployments that will need OAuth support.
|
||||
:::
|
||||
|
||||
:::note
|
||||
If you are storing users in a [database](reference/adapters), we recommend using a different OAuth app for development/production so that you don't mix your test and production user base.
|
||||
:::
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
|
||||
@@ -117,7 +117,7 @@ Using the database strategy is very similar, but instead of preserving the `acce
|
||||
import { Auth } from "@auth/core"
|
||||
import { type TokenSet } from "@auth/core/types"
|
||||
import Google from "@auth/core/providers/google"
|
||||
import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||
import { PrismaClient } from "@prisma/client"
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
@@ -30,7 +30,7 @@ You can override any of the options to suit your own use case.
|
||||
## Configuration
|
||||
|
||||
1. Auth.js does not include `nodemailer` as a dependency, so you'll need to install it yourself if you want to use the Email Provider. Run `npm install nodemailer` or `yarn add nodemailer`.
|
||||
2. You will need an SMTP account; ideally for one of the [services known to work with `nodemailer`](https://community.nodemailer.com/2-0-0-beta/setup-smtp/well-known-services/).
|
||||
2. You will need an SMTP account; such as [the official Nodemailer recommended service](https://nodemailer.com/about/#example) of [Forward Email](https://forwardemail.net).
|
||||
3. There are two ways to configure the SMTP server connection.
|
||||
|
||||
You can either use a connection string or a `nodemailer` configuration object.
|
||||
@@ -40,8 +40,8 @@ You can either use a connection string or a `nodemailer` configuration object.
|
||||
Create an `.env` file to the root of your project and add the connection string and email address.
|
||||
|
||||
```js title=".env" {1}
|
||||
EMAIL_SERVER=smtp://username:password@smtp.example.com:587
|
||||
EMAIL_FROM=noreply@example.com
|
||||
EMAIL_SERVER=smtp://username:password@smtp.forwardemail.net:587
|
||||
EMAIL_FROM=support@example.com
|
||||
```
|
||||
|
||||
Now you can add the email provider like this:
|
||||
@@ -64,7 +64,7 @@ In your `.env` file in the root of your project simply add the configuration obj
|
||||
```js title=".env"
|
||||
EMAIL_SERVER_USER=username
|
||||
EMAIL_SERVER_PASSWORD=password
|
||||
EMAIL_SERVER_HOST=smtp.example.com
|
||||
EMAIL_SERVER_HOST=smtp.forwardemail.net
|
||||
EMAIL_SERVER_PORT=587
|
||||
EMAIL_FROM=noreply@example.com
|
||||
```
|
||||
@@ -112,6 +112,7 @@ providers: [
|
||||
identifier: email,
|
||||
url,
|
||||
provider: { server, from },
|
||||
request // for example can be used to get the user agent (`request.headers.get("user-agent")`) to parse and pass on to the user in the email so they can be more confident they originated the request
|
||||
}) {
|
||||
/* your function */
|
||||
},
|
||||
|
||||
@@ -22,11 +22,18 @@ Next you will have to create some configuration files for Cypress.
|
||||
|
||||
First, the primary cypress config:
|
||||
|
||||
```js title="cypress.json"
|
||||
{
|
||||
"baseUrl": "http://localhost:3000",
|
||||
"chromeWebSecurity": false
|
||||
}
|
||||
```ts title="cypress.config.ts"
|
||||
import { defineConfig } from 'cypress'
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:3000',
|
||||
chromeWebSecurity: false,
|
||||
setupNodeEvents(on, config) {
|
||||
// implement node event listeners here
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
This initial Cypress config will tell Cypress where to find your site on initial launch as well as allow it to open up URLs at domains that aren't your page, for example to be able to login to a social provider.
|
||||
@@ -46,14 +53,24 @@ You must change the login credentials you want to use, but you can also redefine
|
||||
|
||||
Third, if you're using the `cypress-social-login` plugin, you must add this to your `/cypress/plugins/index.js` file like so:
|
||||
|
||||
```js title="cypress/plugins/index.js"
|
||||
const { GoogleSocialLogin } = require("cypress-social-logins").plugins
|
||||
```js title="cypress.config.ts" {3-4,10-14}
|
||||
import { defineConfig } from 'cypress'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { GoogleSocialLogin } = require('cypress-social-logins').plugins
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:3000',
|
||||
chromeWebSecurity: false,
|
||||
setupNodeEvents(on, config) {
|
||||
on('task', {
|
||||
GoogleSocialLogin,
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
module.exports = (on, config) => {
|
||||
on("task", {
|
||||
GoogleSocialLogin: GoogleSocialLogin,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
Finally, you can also add the following npm scripts to your `package.json`:
|
||||
@@ -110,10 +127,6 @@ describe("Login page", () => {
|
||||
secure: cookie.secure,
|
||||
})
|
||||
|
||||
Cypress.Cookies.defaults({
|
||||
preserve: cookieName,
|
||||
})
|
||||
|
||||
// remove the two lines below if you need to stay logged in
|
||||
// for your remaining tests
|
||||
cy.visit("/api/auth/signout")
|
||||
|
||||
@@ -8,6 +8,10 @@ Using an Auth.js / NextAuth.js adapter you can connect to any database service o
|
||||
<a href="/reference/adapter/dgraph" class="adapter-card">
|
||||
<img src="/img/adapters/dgraph.png" width="30" />
|
||||
<h4 class="adapter-card__title">Dgraph Adapter</h4>
|
||||
</a>
|
||||
<a href="/reference/adapter/drizzle" class="adapter-card">
|
||||
<img src="/img/adapters/drizzle-orm.png" width="30" />
|
||||
<h4 class="adapter-card__title">Drizzle Adapter</h4>
|
||||
</a>
|
||||
<a href="/reference/adapter/dynamodb" class="adapter-card">
|
||||
<img src="/img/adapters/dynamodb.png" width="30" />
|
||||
@@ -21,6 +25,10 @@ Using an Auth.js / NextAuth.js adapter you can connect to any database service o
|
||||
<img src="/img/adapters/firebase.svg" width="40" />
|
||||
<h4 class="adapter-card__title">Firebase Adapter</h4>
|
||||
</a>
|
||||
<a href="/reference/adapter/kysely" class="adapter-card">
|
||||
<img src="/img/adapters/kysely.svg" width="40" />
|
||||
<h4 class="adapter-card__title">Kysely Adapter</h4>
|
||||
</a>
|
||||
<a href="/reference/adapter/mikro-orm" class="adapter-card">
|
||||
<img src="/img/adapters/mikro-orm.png" width="30" />
|
||||
<h4 class="adapter-card__title">Mikro ORM Adapter</h4>
|
||||
@@ -67,10 +75,8 @@ Using an Auth.js / NextAuth.js adapter you can connect to any database service o
|
||||
If you don't find an adapter for the database or service you use, you can always create one yourself. Have a look at our guide on [how to create a database adapter](/guides/adapters/creating-a-database-adapter).
|
||||
:::
|
||||
|
||||
|
||||
## Models
|
||||
|
||||
|
||||
Auth.js can be used with any database. Models tell you what structures Auth.js expects from your database. Models will vary slightly depending on which adapter you use, but in general, will look something like this:
|
||||
|
||||
```mermaid
|
||||
@@ -96,8 +102,13 @@ erDiagram
|
||||
string type
|
||||
string provider
|
||||
string providerAccountId
|
||||
string refresh_token
|
||||
string access_token
|
||||
int expires_at
|
||||
string token_type
|
||||
string scope
|
||||
string id_token
|
||||
string session_state
|
||||
}
|
||||
VerificationToken {
|
||||
string identifier
|
||||
@@ -126,7 +137,7 @@ If a user first signs in with an OAuth provider, then their email address is aut
|
||||
This provides a way to contact users and for users to maintain access to their account and sign in using email in the event they are unable to sign in with the OAuth provider in the future (if the [Email Provider](/reference/core/providers_email) is configured).
|
||||
:::
|
||||
|
||||
User creation in the database is automatic and happens when the user is logging in for the first time with a provider.
|
||||
User creation in the database is automatic and happens when the user is logging in for the first time with a provider.
|
||||
If the first sign-in is via the [OAuth Provider](/reference/core/providers_oauth), the default data saved is `id`, `name`, `email` and `image`. You can add more profile data by returning extra fields in your [OAuth provider](/guides/providers/custom-provider)'s [`profile()`](/reference/core/providers#profile) callback.
|
||||
|
||||
If the first sign-in is via the [Email Provider](/reference/core/providers_email), then the saved user will have `id`, `email`, `emailVerified`, where `emailVerified` is the timestamp of when the user was created.
|
||||
@@ -137,7 +148,7 @@ The Account model is for information about OAuth accounts associated with a User
|
||||
|
||||
A single User can have multiple Accounts, but each Account can only have one User.
|
||||
|
||||
Account creation in the database is automatic and happens when the user is logging in for the first time with a provider, or the [`Adapter.linkAccount`](/reference/core/adapters#linkaccount) method is invoked. The default data saved is `access_token`, `refresh_token`, `id_token` and `expires_at`. You can save other fields by returning them in the [OAuth provider](/guides/providers/custom-provider)'s [`account()`](/reference/core/providers#account) callback.
|
||||
Account creation in the database is automatic and happens when the user is logging in for the first time with a provider, or the [`Adapter.linkAccount`](/reference/core/adapters#linkaccount) method is invoked. The default data saved is `access_token`, `expires_at`, `refresh_token`, `id_token`, `token_type`, `scope` and `session_state`. You can save other fields or remove the ones you don't need by returning them in the [OAuth provider](/guides/providers/custom-provider)'s [`account()`](/reference/core/providers#account) callback.
|
||||
|
||||
Linking Accounts to Users happen automatically, only when they have the same e-mail address, and the user is currently signed in. Check the [FAQ](/concepts/faq#security) for more information on why this is a requirement.
|
||||
|
||||
|
||||
7
docs/docs/reference/nextjs/client.md
Normal file
7
docs/docs/reference/nextjs/client.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Client
|
||||
---
|
||||
|
||||
:::warning WIP
|
||||
`@auth/nextjs/client` is work in progress. For now, please use [NextAuth.js Client API](https://next-auth.js.org/getting-started/client).
|
||||
:::
|
||||
7
docs/docs/reference/nextjs/index.md
Normal file
7
docs/docs/reference/nextjs/index.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Next.js Auth
|
||||
---
|
||||
|
||||
:::warning WIP
|
||||
`@auth/nextjs` is work in progress. For now, please use [NextAuth.js](https://next-auth.js.org).
|
||||
:::
|
||||
@@ -38,22 +38,6 @@ function typedocAdapter(name) {
|
||||
]
|
||||
}
|
||||
|
||||
function typedocFramework(id, entrypoints) {
|
||||
return [
|
||||
"docusaurus-plugin-typedoc",
|
||||
{
|
||||
...typedocConfig,
|
||||
id: id.replace("frameworks-", ""),
|
||||
plugin: [require.resolve("./typedoc-mdn-links")],
|
||||
watch: process.env.TYPEDOC_WATCH,
|
||||
entryPoints: entrypoints.map((e) => `../packages/${id}/src/${e}`),
|
||||
tsconfig: `../packages/${id}/tsconfig.json`,
|
||||
out: `reference/${id.replace("frameworks-", "")}`,
|
||||
sidebar: { indexLabel: "index" },
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
/** @type {import("@docusaurus/types").Config} */
|
||||
const docusaurusConfig = {
|
||||
markdown: {
|
||||
@@ -247,34 +231,51 @@ const docusaurusConfig = {
|
||||
],
|
||||
],
|
||||
plugins: [
|
||||
typedocFramework("core", ["index.ts", "adapters.ts", "errors.ts", "jwt.ts", "types.ts"]),
|
||||
typedocFramework("frameworks-sveltekit", ["lib/index.ts", "lib/client.ts"]),
|
||||
typedocFramework("next-auth", ["index.ts", "react.tsx", "jwt.ts", "adapters.ts", "next.ts", "types.ts", "middleware.ts"]),
|
||||
[
|
||||
"docusaurus-plugin-typedoc",
|
||||
{
|
||||
...typedocConfig,
|
||||
id: "core",
|
||||
plugin: [require.resolve("./typedoc-mdn-links")],
|
||||
watch: process.env.TYPEDOC_WATCH,
|
||||
entryPoints: ["index.ts", "adapters.ts", "errors.ts", "jwt.ts", "types.ts"].map((e) => `${coreSrc}/${e}`).concat(providers),
|
||||
tsconfig: "../packages/core/tsconfig.json",
|
||||
out: "reference/core",
|
||||
sidebar: {
|
||||
indexLabel: "index",
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
"docusaurus-plugin-typedoc",
|
||||
{
|
||||
...typedocConfig,
|
||||
id: "sveltekit",
|
||||
plugin: [require.resolve("./typedoc-mdn-links")],
|
||||
watch: process.env.TYPEDOC_WATCH,
|
||||
entryPoints: ["index.ts", "client.ts"].map((e) => `../packages/frameworks-sveltekit/src/lib/${e}`),
|
||||
tsconfig: "../packages/frameworks-sveltekit/tsconfig.json",
|
||||
out: "reference/sveltekit",
|
||||
sidebar: {
|
||||
indexLabel: "index",
|
||||
},
|
||||
},
|
||||
],
|
||||
...(process.env.TYPEDOC_SKIP_ADAPTERS
|
||||
? []
|
||||
: [
|
||||
typedocAdapter("Dgraph"),
|
||||
typedocAdapter("Drizzle"),
|
||||
typedocAdapter("DynamoDB"),
|
||||
typedocAdapter("Fauna"),
|
||||
typedocAdapter("Firebase"),
|
||||
typedocAdapter("Kysely"),
|
||||
typedocAdapter("Mikro ORM"),
|
||||
typedocAdapter("MongoDB"),
|
||||
typedocAdapter("Neo4j"),
|
||||
typedocAdapter("PouchDB"),
|
||||
typedocAdapter("Prisma"),
|
||||
[
|
||||
"docusaurus-plugin-typedoc",
|
||||
{
|
||||
...typedocConfig,
|
||||
id: "typeorm",
|
||||
plugin: [require.resolve("./typedoc-mdn-links")],
|
||||
watch: process.env.TYPEDOC_WATCH,
|
||||
entryPoints: [`../packages/adapter-typeorm-legacy/src/index.ts`],
|
||||
tsconfig: `../packages/adapter-typeorm-legacy/tsconfig.json`,
|
||||
out: `reference/adapter/typeorm`,
|
||||
sidebar: { indexLabel: "TypeORM" },
|
||||
},
|
||||
],
|
||||
typedocAdapter("TypeORM"),
|
||||
typedocAdapter("Sequelize"),
|
||||
typedocAdapter("Supabase"),
|
||||
typedocAdapter("Upstash Redis"),
|
||||
|
||||
@@ -35,9 +35,16 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "next-auth",
|
||||
link: { type: "doc", id: "reference/next-auth/index" },
|
||||
items: [{ type: "autogenerated", dirName: "reference/next-auth" }],
|
||||
label: "@auth/nextjs",
|
||||
link: { type: "doc", id: "reference/nextjs/index" },
|
||||
items: [
|
||||
"reference/nextjs/client",
|
||||
{
|
||||
type: "link",
|
||||
label: "NextAuth.js (next-auth)",
|
||||
href: "https://next-auth.js.org",
|
||||
},
|
||||
],
|
||||
},
|
||||
...(process.env.TYPEDOC_SKIP_ADAPTERS
|
||||
? []
|
||||
@@ -48,9 +55,11 @@ module.exports = {
|
||||
link: { type: "doc", id: "reference/adapters/index" },
|
||||
items: [
|
||||
{ type: "doc", id: "reference/adapter/dgraph/index" },
|
||||
{ type: "doc", id: "reference/adapter/drizzle/index" },
|
||||
{ type: "doc", id: "reference/adapter/dynamodb/index" },
|
||||
{ type: "doc", id: "reference/adapter/fauna/index" },
|
||||
{ type: "doc", id: "reference/adapter/firebase/index" },
|
||||
{ type: "doc", id: "reference/adapter/kysely/index" },
|
||||
{ type: "doc", id: "reference/adapter/mikro-orm/index" },
|
||||
{ type: "doc", id: "reference/adapter/mongodb/index" },
|
||||
{ type: "doc", id: "reference/adapter/neo4j/index" },
|
||||
|
||||
@@ -7,6 +7,7 @@ const icons = [
|
||||
"/img/providers/apple.svg",
|
||||
"/img/providers/auth0.svg",
|
||||
"/img/providers/cognito.svg",
|
||||
"/img/providers/descope.svg",
|
||||
"/img/providers/battlenet.svg",
|
||||
"/img/providers/box.svg",
|
||||
"/img/providers/facebook.svg",
|
||||
|
||||
@@ -29,6 +29,7 @@ html[data-theme="dark"] .adapter-card {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] .adapter-card:hover,
|
||||
.adapter-card:hover {
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
|
||||
@@ -91,7 +91,7 @@ html[data-theme="dark"] .navbar__item.navbar__link[href*="npm"]:before {
|
||||
position: absolute;
|
||||
color: #000;
|
||||
top: -10px;
|
||||
right: -45px;
|
||||
right: 4px;
|
||||
font-size: 9px;
|
||||
background-color: #ccc;
|
||||
padding: 2px 5px;
|
||||
|
||||
@@ -101,13 +101,13 @@ export default function Home() {
|
||||
.fetch("https://api.github.com/repos/nextauthjs/next-auth")
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
const navLinks = document.getElementsByClassName(
|
||||
"navbar__item navbar__link"
|
||||
const githubLink = document.querySelector(
|
||||
".navbar__item.navbar__link[href*='github']"
|
||||
)
|
||||
const githubStat = document.createElement("span")
|
||||
githubStat.innerHTML = kFormatter(data.stargazers_count)
|
||||
githubStat.className = "github-counter"
|
||||
navLinks[4].appendChild(githubStat)
|
||||
githubLink.appendChild(githubStat)
|
||||
})
|
||||
}, [])
|
||||
return (
|
||||
|
||||
BIN
docs/static/img/adapters/drizzle-orm.png
vendored
Normal file
BIN
docs/static/img/adapters/drizzle-orm.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
14
docs/static/img/adapters/kysely.svg
vendored
Normal file
14
docs/static/img/adapters/kysely.svg
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg width="132" height="132" viewBox="0 0 132 132" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_8_3)">
|
||||
<rect x="2" y="2" width="128" height="128" rx="16" fill="white" />
|
||||
<path
|
||||
d="M41.2983 109V23.9091H46.4918V73.31H47.0735L91.9457 23.9091H98.8427L61.9062 64.1694L98.5103 109H92.0288L58.5824 67.9087L46.4918 81.2873V109H41.2983Z"
|
||||
fill="black" />
|
||||
</g>
|
||||
<rect x="2" y="2" width="128" height="128" rx="16" stroke="#121212" stroke-width="4" />
|
||||
<defs>
|
||||
<clipPath id="clip0_8_3">
|
||||
<rect x="2" y="2" width="128" height="128" rx="16" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 637 B |
50
docs/static/img/providers/descope.svg
vendored
Normal file
50
docs/static/img/providers/descope.svg
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 26.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="194.7px" height="215.2px" viewBox="0 0 194.7 215.2" style="enable-background:new 0 0 194.7 215.2;" xml:space="preserve"
|
||||
>
|
||||
<style type="text/css">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
.st1{fill:url(#SVGID_00000004519561486438896460000001266960168497785022_);}
|
||||
.st2{fill:url(#SVGID_00000049204468076180615810000015113731544435055266_);}
|
||||
.st3{fill:url(#SVGID_00000116951257355544416270000003794629356563808950_);}
|
||||
</style>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="68.3919" y1="222.1531" x2="185.0265" y2="41.0264">
|
||||
<stop offset="1.481436e-07" style="stop-color:#0083B5"/>
|
||||
<stop offset="0.4173" style="stop-color:#00FFFF"/>
|
||||
<stop offset="0.9952" style="stop-color:#6FF12D"/>
|
||||
</linearGradient>
|
||||
<path class="st0" d="M129.8,174.7c7.6-1.6,14-4.8,19.2-9.7c7.7-7.3,8.8-17.1,8.8-29.4V80.7c0-12.3-1.1-22.1-8.8-29.4
|
||||
c-5.2-4.9-11.6-8.1-19.2-9.7V15.4c12.5,1.8,22.9,6.5,31,14.2c10.6,10,19.9,23.5,19.9,40.5v75c0,17-9.3,30.5-19.9,40.5
|
||||
c-8.1,7.7-18.5,12.4-31,14.2V174.7z"/>
|
||||
|
||||
<linearGradient id="SVGID_00000040544740507634666800000017273841385603649669_" gradientUnits="userSpaceOnUse" x1="5.037" y1="181.3564" x2="121.6716" y2="0.2297">
|
||||
<stop offset="1.481436e-07" style="stop-color:#0083B5"/>
|
||||
<stop offset="0.4173" style="stop-color:#00FFFF"/>
|
||||
<stop offset="0.9952" style="stop-color:#6FF12D"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000040544740507634666800000017273841385603649669_);" d="M33.9,29.6c8.1-7.7,18.5-12.4,31-14.2
|
||||
v26.3c-7.6,1.6-14,4.8-19.2,9.7c-7.7,7.3-8.8,17-8.8,29.2v55.1c0,12.3,1.1,22.1,8.8,29.4c5.2,4.9,11.6,8.1,19.2,9.7v25.1
|
||||
c-12.5-1.8-22.9-6.5-31-14.2c-10.6-10-19.9-23.5-19.9-40.5V69.8C13.9,53,23.2,39.6,33.9,29.6z"/>
|
||||
<g>
|
||||
|
||||
<linearGradient id="SVGID_00000060713993868866928010000000698955780952733088_" gradientUnits="userSpaceOnUse" x1="22.0278" y1="192.2974" x2="138.6624" y2="11.1707">
|
||||
<stop offset="1.481436e-07" style="stop-color:#0083B5"/>
|
||||
<stop offset="0.4173" style="stop-color:#00FFFF"/>
|
||||
<stop offset="0.9952" style="stop-color:#6FF12D"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000060713993868866928010000000698955780952733088_);" d="M120.2,87.8l8.5-13.7l-17.8-9.4
|
||||
l-7.5,14.2c-1.1,2.1-3.1,3.3-5.5,3.3c-2.3,0-4.4-1.2-5.5-3.3L85,64.7L67.3,74l12.3,19.7L120.2,87.8z"/>
|
||||
|
||||
<linearGradient id="SVGID_00000115475840050352750520000000840372054167564949_" gradientUnits="userSpaceOnUse" x1="37.9651" y1="202.5601" x2="154.5998" y2="21.4334">
|
||||
<stop offset="1.481436e-07" style="stop-color:#0083B5"/>
|
||||
<stop offset="0.4173" style="stop-color:#00FFFF"/>
|
||||
<stop offset="0.9952" style="stop-color:#6FF12D"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000115475840050352750520000000840372054167564949_);" d="M142.4,97.7l-87.8,0.8v17.7l27.5-0.1
|
||||
l-14.8,23.8l17.7,9.3l7.5-14.2c1.1-2.1,3.1-3.3,5.5-3.3c2.3,0,4.4,1.2,5.5,3.3l7.5,14.2l17.8-9.4l-12-19.3L93.7,116l48.7-0.2V97.7
|
||||
z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
11
docs/static/img/providers/passage.svg
vendored
Normal file
11
docs/static/img/providers/passage.svg
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.8" d="M37.8419 71.6921L65.1425 87.4541C86.2537 99.6426 93.4921 126.639 81.3036 147.75C80.2315 149.607 79.045 151.353 77.7583 152.989L12.6182 115.381C8.67588 113.105 5.58417 109.922 3.44179 106.254C-0.964934 98.6912 -1.30613 89.0446 3.38448 80.9202C10.348 68.8591 25.7752 64.7254 37.8419 71.6921Z" fill="#3D53F6"/>
|
||||
<path opacity="0.5" d="M37.8419 180.052L65.1425 164.29C86.2537 152.101 93.4921 125.105 81.3036 103.994C80.2315 102.137 79.045 100.391 77.7583 98.7544L12.6182 136.363C8.67588 138.639 5.58417 141.822 3.44179 145.49C-0.964934 153.053 -1.30613 162.699 3.38448 170.824C10.348 182.885 25.7752 187.019 37.8419 180.052Z" fill="#3D53F6"/>
|
||||
<path opacity="0.5" d="M212.753 71.6921L185.452 87.4541C164.341 99.6426 157.103 126.639 169.291 147.75C170.363 149.607 171.55 151.353 172.836 152.989L237.976 115.381C241.919 113.105 245.01 109.922 247.153 106.254C251.56 98.6912 251.901 89.0446 247.21 80.9202C240.247 68.8591 224.819 64.7254 212.753 71.6921Z" fill="#3D53F6"/>
|
||||
<path opacity="0.8" d="M212.753 180.052L185.452 164.29C164.341 152.101 157.103 125.105 169.291 103.994C170.363 102.137 171.55 100.391 172.836 98.7544L237.976 136.363C241.919 138.639 245.01 141.822 247.153 145.49C251.56 153.053 251.901 162.699 247.21 170.824C240.247 182.885 224.819 187.019 212.753 180.052Z" fill="#3D53F6"/>
|
||||
<path d="M125.297 150.525C139.228 150.525 150.52 139.232 150.52 125.302C150.52 111.372 139.228 100.079 125.297 100.079C111.367 100.079 100.075 111.372 100.075 125.302C100.075 139.232 111.367 150.525 125.297 150.525Z" fill="#FF2F1D"/>
|
||||
<path opacity="0.8" d="M71.1172 212.753L86.8793 185.452C99.0678 164.341 126.064 157.102 147.175 169.291C149.032 170.363 150.778 171.55 152.415 172.836L114.806 237.976C112.53 241.919 109.347 245.01 105.679 247.153C98.1164 251.559 88.4698 251.901 80.3454 247.21C68.2842 240.247 64.1505 224.819 71.1172 212.753Z" fill="#FF2F1D"/>
|
||||
<path opacity="0.5" d="M179.477 212.752L163.715 185.452C151.526 164.341 124.53 157.102 103.419 169.291C101.562 170.363 99.8157 171.549 98.1794 172.836L135.788 237.976C138.064 241.919 141.247 245.01 144.915 247.153C152.478 251.559 162.124 251.901 170.249 247.21C182.31 240.246 186.444 224.819 179.477 212.752Z" fill="#FF2F1D"/>
|
||||
<path opacity="0.5" d="M71.1172 37.8419L86.8793 65.1425C99.0678 86.2537 126.064 93.4921 147.175 81.3036C149.032 80.2315 150.778 79.045 152.415 77.7583L114.806 12.6182C112.53 8.67589 109.347 5.58416 105.679 3.44179C98.1164 -0.964936 88.4698 -1.30613 80.3454 3.38449C68.2842 10.348 64.1505 25.7752 71.1172 37.8419Z" fill="#3D53F6"/>
|
||||
<path opacity="0.8" d="M179.477 37.8419L163.715 65.1425C151.526 86.2537 124.53 93.4921 103.419 81.3036C101.562 80.2315 99.8157 79.045 98.1794 77.7583L135.788 12.6182C138.064 8.67589 141.247 5.58416 144.915 3.44179C152.478 -0.964936 162.124 -1.30613 170.249 3.38449C182.31 10.348 186.444 25.7752 179.477 37.8419Z" fill="#3D53F6"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "https://openapi.vercel.sh/vercel.json",
|
||||
"cleanUrls": true,
|
||||
"headers": [
|
||||
{
|
||||
@@ -76,10 +77,15 @@
|
||||
"has": [{ "type": "host", "value": "warnings.authjs.dev" }],
|
||||
"destination": "https://authjs.dev/reference/warnings/:path*"
|
||||
},
|
||||
{
|
||||
"source": "/",
|
||||
"has": [{ "type": "host", "value": "adapters.authjs.dev" }],
|
||||
"destination": "https://authjs.dev/reference/adapters"
|
||||
},
|
||||
{
|
||||
"source": "/:path(.*)",
|
||||
"has": [{ "type": "host", "value": "adapters.authjs.dev" }],
|
||||
"destination": "https://authjs.dev/reference/adapters/:path*"
|
||||
"destination": "https://authjs.dev/reference/adapter/:path*"
|
||||
},
|
||||
{
|
||||
"source": "/:path",
|
||||
|
||||
15
package.json
15
package.json
@@ -7,9 +7,8 @@
|
||||
"build:app": "turbo run build --filter=next-auth-app",
|
||||
"build:docs": "turbo run build --filter=docs",
|
||||
"build": "turbo run build --filter=next-auth --filter=@next-auth/* --filter=@auth/* --no-deps",
|
||||
"test": "turbo run test --concurrency=1 --filter=[HEAD^1] --filter=./packages/* --filter=!@*upstash* --filter=!*dynamodb-*",
|
||||
"test": "turbo run test --concurrency=1 --filter=[HEAD^1] --filter=./packages/* --filter=!@*upstash* --filter=!*dynamodb-* --filter=!*app*",
|
||||
"clean": "turbo run clean --no-cache",
|
||||
"dev:example": "turbo run dev --parallel --continue --filter=nextjs-example-app... --filter=!./packages/adapter-*",
|
||||
"dev:db": "turbo run dev --parallel --continue --filter=next-auth-app...",
|
||||
"dev": "turbo run dev --parallel --continue --filter=next-auth-app... --filter=!./packages/adapter-*",
|
||||
"dev-v4:db": "turbo run dev --parallel --continue --filter=next-auth-app-v4...",
|
||||
@@ -29,7 +28,7 @@
|
||||
"@actions/core": "^1.10.0",
|
||||
"@balazsorban/monorepo-release": "0.1.8",
|
||||
"@types/jest": "^28.1.3",
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/node": "^17.0.25",
|
||||
"@typescript-eslint/eslint-plugin": "5.47.0",
|
||||
"@typescript-eslint/parser": "5.47.0",
|
||||
"eslint": "8.30.0",
|
||||
@@ -44,7 +43,7 @@
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"prettier": "2.8.1",
|
||||
"prettier-plugin-svelte": "^2.8.1",
|
||||
"turbo": "1.8.8",
|
||||
"turbo": "^1.10.3",
|
||||
"typescript": "4.9.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -97,6 +96,8 @@
|
||||
"packages/core/src/lib/pages/styles.ts",
|
||||
"packages/frameworks-sveltekit/package",
|
||||
"packages/frameworks-sveltekit/vite.config.{js,ts}.timestamp-*",
|
||||
"packages/next-auth/src/providers/oauth-types.ts",
|
||||
"packages/next-auth/css/index.css",
|
||||
".branches",
|
||||
"db.sqlite",
|
||||
"dev.db",
|
||||
@@ -247,10 +248,8 @@
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"apps/dev/nextjs/pages/api/auth-old/[...nextauth].ts",
|
||||
"apps/dev/nextjs/app/api/auth/[...nextauth]/route.ts",
|
||||
"docs/{sidebars,docusaurus.config}.js",
|
||||
"packages/next-auth/src/lib/env.ts"
|
||||
"apps/dev/nextjs/pages/api/auth/[...nextauth].ts",
|
||||
"docs/{sidebars,docusaurus.config}.js"
|
||||
],
|
||||
"options": {
|
||||
"printWidth": 150
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -8,14 +8,14 @@
|
||||
</a>
|
||||
<h3 align="center"><b>Dgraph Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||
<p align="center" style="align: center;">
|
||||
<a href="https://npm.im/@next-auth/dgraph-adapter">
|
||||
<a href="https://npm.im/@auth/dgraph-adapter">
|
||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||
</a>
|
||||
<a href="https://npm.im/@next-auth/dgraph-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/dgraph-adapter?color=green&label=@next-auth/dgraph-adapter&style=flat-square">
|
||||
<a href="https://npm.im/@auth/dgraph-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@auth/dgraph-adapter?color=green&label=@auth/dgraph-adapter&style=flat-square">
|
||||
</a>
|
||||
<a href="https://www.npmtrends.com/@next-auth/dgraph-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@next-auth/dgraph-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||
<a href="https://www.npmtrends.com/@auth/dgraph-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@auth/dgraph-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||
</a>
|
||||
<a href="https://github.com/nextauthjs/next-auth/stargazers">
|
||||
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="Github Stars" />
|
||||
|
||||
@@ -1,19 +1,30 @@
|
||||
{
|
||||
"name": "@next-auth/dgraph-adapter",
|
||||
"version": "1.0.6",
|
||||
"description": "Dgraph adapter for next-auth.",
|
||||
"name": "@auth/dgraph-adapter",
|
||||
"version": "1.0.0",
|
||||
"description": "Dgraph adapter for Auth.js",
|
||||
"homepage": "https://authjs.dev",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
"author": "Arnaud Derbey <arnaud@derbey.dev>",
|
||||
"contributors": [],
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
"dist",
|
||||
"index.d.ts"
|
||||
"contributors": [
|
||||
"Balázs Orbán <info@balazsorban.com>"
|
||||
],
|
||||
"type": "module",
|
||||
"types": "./index.d.ts",
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.d.ts*",
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./index.js"
|
||||
}
|
||||
},
|
||||
"license": "ISC",
|
||||
"keywords": [
|
||||
"next-auth",
|
||||
@@ -29,10 +40,6 @@
|
||||
"build": "tsc",
|
||||
"test": "./tests/test.sh"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"next-auth": "^4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:*",
|
||||
"@next-auth/tsconfig": "workspace:*",
|
||||
@@ -40,12 +47,12 @@
|
||||
"@types/jsonwebtoken": "^8.5.5",
|
||||
"@types/node-fetch": "^2.5.11",
|
||||
"jest": "^27.4.3",
|
||||
"next-auth": "workspace:*",
|
||||
"ts-jest": "^27.0.3"
|
||||
"ts-jest": "^27.0.3",
|
||||
"undici": "5.22.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"node-fetch": "^2.6.1"
|
||||
"@auth/core": "workspace:*",
|
||||
"jsonwebtoken": "^8.5.1"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user