mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
55 Commits
@auth/core
...
@auth/dyna
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
6111662df7 | ||
|
|
5da6549c48 |
14
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
14
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
@@ -21,19 +21,19 @@ body:
|
||||
multiple: true
|
||||
options:
|
||||
- "Custom adapter"
|
||||
- "@next-auth/dgraph-adapter"
|
||||
- "@next-auth/dynamodb-adapter"
|
||||
- "@auth/dgraph-adapter"
|
||||
- "@auth/dynamodb-adapter"
|
||||
- "@next-auth/fauna-adapter"
|
||||
- "@next-auth/firebase-adapter"
|
||||
- "@next-auth/mikro-orm-adapter"
|
||||
- "@next-auth/mongodb-adapter"
|
||||
- "@auth/mikro-orm-adapter"
|
||||
- "@auth/mongodb-adapter"
|
||||
- "@next-auth/neo4j-adapter"
|
||||
- "@next-auth/pouchdb-adapter"
|
||||
- "@next-auth/prisma-adapter"
|
||||
- "@auth/prisma-adapter"
|
||||
- "@next-auth/sequelize-adapter"
|
||||
- "@next-auth/supabase-adapter"
|
||||
- "@next-auth/typeorm-legacy-adapter"
|
||||
- "@next-auth/upstash-redis-adapter"
|
||||
- "@auth/typeorm-adapter"
|
||||
- "@auth/upstash-redis-adapter"
|
||||
- "@next-auth/xata-adapter"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
16
.github/issue-labeler.yml
vendored
16
.github/issue-labeler.yml
vendored
@@ -1,10 +1,10 @@
|
||||
# https://github.com/github/issue-labeler#basic-examples
|
||||
|
||||
dgraph:
|
||||
- "@next-auth/dgraph-adapter"
|
||||
- "@auth/dgraph-adapter"
|
||||
|
||||
dynamodb:
|
||||
- "@next-auth/dynamodb-adapter"
|
||||
- "@auth/dynamodb-adapter"
|
||||
|
||||
fauna:
|
||||
- "@next-auth/fauna-adapter"
|
||||
@@ -13,10 +13,10 @@ firebase:
|
||||
- "@next-auth/firebase-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"
|
||||
@@ -25,7 +25,7 @@ pouchdb:
|
||||
- "@next-auth/pouchdb-adapter"
|
||||
|
||||
prisma:
|
||||
- "@next-auth/prisma-adapter"
|
||||
- "@auth/prisma-adapter"
|
||||
|
||||
sequelize:
|
||||
- "@next-auth/sequelize-adapter"
|
||||
@@ -33,11 +33,11 @@ sequelize:
|
||||
supabase:
|
||||
- "@next-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"
|
||||
|
||||
2
.github/pr-labeler.yml
vendored
2
.github/pr-labeler.yml
vendored
@@ -21,6 +21,6 @@ solidjs: ["packages/frameworks-solid-start/**/*"]
|
||||
supabase: ["packages/adapter-supabase/**/*"]
|
||||
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))
|
||||
|
||||
84
.github/workflows/release.yml
vendored
84
.github/workflows/release.yml
vendored
@@ -8,6 +8,54 @@ 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"
|
||||
|
||||
jobs:
|
||||
test:
|
||||
@@ -24,6 +72,7 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Run tests
|
||||
@@ -73,6 +122,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 +147,7 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Determine version
|
||||
@@ -122,3 +173,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 }}
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -38,6 +38,7 @@ packages/next-auth/next
|
||||
packages/*/*.js
|
||||
packages/*/*.d.ts
|
||||
packages/*/*.d.ts.map
|
||||
packages/*/lib
|
||||
|
||||
# Development app
|
||||
apps/dev/src/css
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@next-auth/fauna-adapter": "workspace:*",
|
||||
"@next-auth/prisma-adapter": "workspace:*",
|
||||
"@auth/prisma-adapter": "workspace:*",
|
||||
"@next-auth/supabase-adapter": "workspace:*",
|
||||
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
||||
"@auth/typeorm-adapter": "workspace:*",
|
||||
"@prisma/client": "^3",
|
||||
"@supabase/supabase-js": "^2.0.5",
|
||||
"faunadb": "^4",
|
||||
|
||||
@@ -37,7 +37,7 @@ 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)
|
||||
@@ -51,8 +51,8 @@ import WorkOS from "next-auth/providers/workos"
|
||||
// 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",
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*",
|
||||
"@next-auth/fauna-adapter": "workspace:*",
|
||||
"@next-auth/prisma-adapter": "workspace:*",
|
||||
"@auth/prisma-adapter": "workspace:*",
|
||||
"@next-auth/supabase-adapter": "workspace:*",
|
||||
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
||||
"@auth/typeorm-adapter": "workspace:*",
|
||||
"@prisma/client": "^3",
|
||||
"@supabase/supabase-js": "^2.0.5",
|
||||
"faunadb": "^4",
|
||||
|
||||
@@ -41,7 +41,7 @@ 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)
|
||||
@@ -55,8 +55,8 @@ import WorkOS from "@auth/core/providers/workos"
|
||||
// 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",
|
||||
|
||||
@@ -7,7 +7,7 @@ export default function Page() {
|
||||
<p>Only admin users can see this page.</p>
|
||||
<p>
|
||||
To learn more about the NextAuth middleware see
|
||||
<a href="https://docs-git-misc-docs-nextauthjs.vercel.app/configuration/nextjs#middleware">
|
||||
<a href="https://next-auth.js.org/configuration/nextjs#middleware">
|
||||
the docs
|
||||
</a>
|
||||
.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -269,7 +269,7 @@ Ultimately if your request is not accepted or is not actively in development, yo
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
Auth.js by default uses JSON Web Tokens for saving the user's session. However, if you use a [database adapter](/guides/adapters/using-a-database-adapter), the database will be used to persist the user's session. You can force the usage of JWT when using a database [through the configuration options](/reference/configuration/auth-config#session). Since v4 all our JWT tokens are now encrypted by default with A256GCM.
|
||||
Auth.js by default uses JSON Web Tokens for saving the user's session. However, if you use a [database adapter](/guides/adapters/using-a-database-adapter), the database will be used to persist the user's session. You can force the usage of JWT when using a database [through the configuration options](/reference/configuration/auth-config#session). Since v4 all our JWTs are now encrypted by default with A256GCM.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -243,10 +243,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**:
|
||||
|
||||
@@ -6,7 +6,7 @@ Using a custom adapter you can connect to any database back-end or even several
|
||||
|
||||
## How to create an adapter
|
||||
|
||||
For more information about the data these methods need to manage see [models](/reference/adapters/models).
|
||||
For more information about the data these methods need to manage see [models](/reference/adapters#models).
|
||||
|
||||
_See the code below for practical example._
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ Sent when the user signs out.
|
||||
|
||||
The message object will contain one of these depending on if you use JWT or database persisted sessions:
|
||||
|
||||
- `token`: The JWT token for this session.
|
||||
- `token`: The JWT for this session.
|
||||
- `session`: The session object from your adapter that is being ended
|
||||
|
||||
### createUser
|
||||
@@ -60,5 +60,5 @@ Sent at the end of a request for the current session.
|
||||
|
||||
The message object will contain one of these depending on if you use JWT or database persisted sessions:
|
||||
|
||||
- `token`: The JWT token for this session.
|
||||
- `token`: The JWT for this session.
|
||||
- `session`: The session object from your adapter.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Overview
|
||||
---
|
||||
|
||||
Using a Auth.js / NextAuth.js adapter you can connect to any database service or even several different services at the same time. The following listed official adapters are created and maintained by the community:
|
||||
Using an Auth.js / NextAuth.js adapter you can connect to any database service or even several different services at the same time. The following listed official adapters are created and maintained by the community:
|
||||
|
||||
<div class="adapter-card-list">
|
||||
<a href="/reference/adapter/dgraph" class="adapter-card">
|
||||
@@ -71,7 +71,7 @@ If you don't find an adapter for the database or service you use, you can always
|
||||
## 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. Each adapter's model/schema will be slightly adapted for its needs, but will look very much like this schema below:
|
||||
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
|
||||
erDiagram
|
||||
@@ -103,8 +103,6 @@ erDiagram
|
||||
string scope
|
||||
string id_token
|
||||
string session_state
|
||||
string oauth_token_secret
|
||||
string oauth_token
|
||||
}
|
||||
VerificationToken {
|
||||
string identifier
|
||||
@@ -113,10 +111,10 @@ erDiagram
|
||||
}
|
||||
```
|
||||
|
||||
More information about each Model / Table can be found below.
|
||||
More information about each Model/Table can be found below.
|
||||
|
||||
:::note
|
||||
You can [create your own adapter](/guides/adapters/creating-a-database-adapter) if you want to use Auth.js with a database that is not supported out of the box, or you have to change fields on any of the models.
|
||||
You can [create your adapter](/guides/adapters/creating-a-database-adapter) if you want to use Auth.js with a database that is not supported out of the box, or you have to change fields on any of the models.
|
||||
:::
|
||||
|
||||
---
|
||||
@@ -125,30 +123,31 @@ You can [create your own adapter](/guides/adapters/creating-a-database-adapter)
|
||||
|
||||
The User model is for information such as the user's name and email address.
|
||||
|
||||
Email address is optional, but if one is specified for a User then it must be unique.
|
||||
Email address is optional, but if one is specified for a User, then it must be unique.
|
||||
|
||||
:::note
|
||||
If a user first signs in with OAuth then their email address is automatically populated using the one from their OAuth profile, if the OAuth provider returns one.
|
||||
If a user first signs in with an OAuth provider, then their email address is automatically populated using the one from their OAuth profile if the OAuth provider returns one.
|
||||
|
||||
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 future (if the [Email Provider](/getting-started/email-tutorial) is configured).
|
||||
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. 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.
|
||||
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.
|
||||
|
||||
### Account
|
||||
|
||||
The Account model is for information about OAuth accounts associated with a User. It will usually contain `access_token`, `id_token` and other OAuth specific data. [`TokenSet`](https://github.com/panva/node-openid-client/blob/main/docs/README.md#new-tokensetinput) from `openid-client` might give you an idea of all the fields.
|
||||
|
||||
:::note
|
||||
In case of an OAuth 1.0 provider (like Twitter), you will have to look for `oauth_token` and `oauth_token_secret` string fields. GitHub also has an extra `refresh_token_expires_in` integer field. You have to make sure that your database schema includes these fields.
|
||||
:::
|
||||
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.
|
||||
|
||||
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 why this is a requirement.
|
||||
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.
|
||||
|
||||
:::tip
|
||||
You can manually unlink accounts, if your adapter implements the `unlinkAccount` method. Make sure to take all the necessary security steps to avoid data loss.
|
||||
You can manually unlink accounts if your adapter implements the `unlinkAccount` method. Make sure to take all the necessary security steps to avoid data loss.
|
||||
:::
|
||||
|
||||
:::note
|
||||
@@ -162,7 +161,7 @@ The Session model is used for database sessions. It is not used if JSON Web Toke
|
||||
A single User can have multiple Sessions, each Session can only have one User.
|
||||
|
||||
:::tip
|
||||
When a Session is read, we check if it's `expires` field indicates an invalid session, and delete it from the database. You can also do this clean-up periodically in the background to avoid our extra delete call to the database during an active session retrieval. This might result in a slight performance increase in a few cases.
|
||||
When a Session is read, we check if its `expires` field indicates an invalid session, and delete it from the database. You can also do this clean-up periodically in the background to avoid our extra delete call to the database during an active session retrieval. This might result in a slight performance increase in a few cases.
|
||||
:::
|
||||
|
||||
### Verification Token
|
||||
@@ -171,7 +170,7 @@ The Verification Token model is used to store tokens for passwordless sign in.
|
||||
|
||||
A single User can have multiple open Verification Tokens (e.g. to sign in to different devices).
|
||||
|
||||
It has been designed to be extendable for other verification purposes in the future (e.g. 2FA / short codes).
|
||||
It has been designed to be extendable for other verification purposes in the future (e.g. 2FA / magic codes, etc.).
|
||||
|
||||
:::note
|
||||
Auth.js makes sure that every token is usable only once, and by default has a short (1 day, can be configured by [`maxAge`](/guides/providers/email)) lifetime. If your user did not manage to finish the sign-in flow in time, they will have to start the sign-in process again.
|
||||
@@ -183,8 +182,7 @@ Due to users forgetting or failing at the sign-in flow, you might end up with un
|
||||
|
||||
## RDBMS Naming Convention
|
||||
|
||||
Auth.js / NextAuth.js uses `camelCase` for its own database rows, while respecting the conventional `snake_case` formatting for OAuth related values. If mixed casing is an issue for you, most adapters have a dedicated section on how to use a single naming convention.
|
||||
|
||||
Auth.js / NextAuth.js uses `camelCase` for its database rows while respecting the conventional `snake_case` formatting for OAuth-related values. If the mixed casing is an issue for you, most adapters have a dedicated documentation section on how to force a casing convention.
|
||||
|
||||
## TypeScript
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ const path = require("path")
|
||||
const coreSrc = "../packages/core/src"
|
||||
const providers = fs
|
||||
.readdirSync(path.join(__dirname, coreSrc, "/providers"))
|
||||
.filter((file) => file.endsWith(".ts") && !file.startsWith("oauth"))
|
||||
.filter((file) => file.endsWith(".ts"))
|
||||
.map((p) => `${coreSrc}/providers/${p}`)
|
||||
|
||||
const typedocConfig = require("./typedoc.json")
|
||||
@@ -273,19 +273,7 @@ const docusaurusConfig = {
|
||||
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"),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -43,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.1",
|
||||
"typescript": "4.9.4"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -9,18 +9,18 @@
|
||||
* ## Installation
|
||||
*
|
||||
* ```bash npm2yarn2pnpm
|
||||
* npm install next-auth @next-auth/dgraph-adapter
|
||||
* npm install next-auth @auth/dgraph-adapter
|
||||
* ```
|
||||
*
|
||||
* @module @next-auth/dgraph-adapter
|
||||
* @module @auth/dgraph-adapter
|
||||
*/
|
||||
import { client as dgraphClient } from "./client"
|
||||
import { format } from "./utils"
|
||||
import type { Adapter } from "next-auth/adapters"
|
||||
import type { DgraphClientParams } from "./client"
|
||||
import * as defaultFragments from "./graphql/fragments"
|
||||
import { client as dgraphClient } from "./lib/client"
|
||||
import { format } from "./lib/utils"
|
||||
import type { Adapter } from "@auth/core/adapters"
|
||||
import type { DgraphClientParams } from "./lib/client"
|
||||
import * as defaultFragments from "./lib/graphql/fragments"
|
||||
|
||||
export type { DgraphClientParams, DgraphClientError } from "./client"
|
||||
export type { DgraphClientParams, DgraphClientError } from "./lib/client"
|
||||
|
||||
/** This is the interface of the Dgraph adapter options. */
|
||||
export interface DgraphAdapterOptions {
|
||||
@@ -28,7 +28,7 @@ export interface DgraphAdapterOptions {
|
||||
* The GraphQL {@link https://dgraph.io/docs/query-language/fragments/ Fragments} you can supply to the adapter
|
||||
* to define how the shapes of the `user`, `account`, `session`, `verificationToken` entities look.
|
||||
*
|
||||
* By default the adapter will uses the [default defined fragments](https://github.com/nextauthjs/next-auth/blob/main/packages/adapter-dgraph/src/graphql/fragments.ts)
|
||||
* By default the adapter will uses the [default defined fragments](https://github.com/nextauthjs/next-auth/blob/main/packages/adapter-dgraph/src/lib/graphql/fragments.ts)
|
||||
* , this config option allows to extend them.
|
||||
*/
|
||||
fragments?: {
|
||||
@@ -48,7 +48,7 @@ export { format }
|
||||
*
|
||||
* ```ts title="pages/api/auth/[...nextauth].js"
|
||||
* import NextAuth from "next-auth"
|
||||
* import { DgraphAdapter } from "@next-auth/dgraph-adapter"
|
||||
* import { DgraphAdapter } from "@auth/dgraph-adapter"
|
||||
*
|
||||
* export default NextAuth({
|
||||
* providers: [],
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import * as jwt from "jsonwebtoken"
|
||||
import fetch from "node-fetch"
|
||||
|
||||
import type { HeadersInit } from "node-fetch"
|
||||
|
||||
export interface DgraphClientParams {
|
||||
endpoint: string
|
||||
@@ -1,12 +1,14 @@
|
||||
import { DgraphAdapter, format } from "../src"
|
||||
import { client as dgraphClient } from "../src/client"
|
||||
import * as fragments from "../src/graphql/fragments"
|
||||
import { client as dgraphClient } from "../src/lib/client"
|
||||
import * as fragments from "../src/lib/graphql/fragments"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import fs from "fs"
|
||||
import path from "path"
|
||||
|
||||
import type { DgraphClientParams } from "../src"
|
||||
|
||||
globalThis.fetch ??= require("undici").fetch
|
||||
|
||||
const params: DgraphClientParams = {
|
||||
endpoint: "http://localhost:8080/graphql",
|
||||
authToken: "test",
|
||||
|
||||
@@ -21,7 +21,7 @@ dgraph/standalone
|
||||
|
||||
echo "Waiting 15 sec for db to start..." && sleep 15
|
||||
|
||||
head -n -1 src/graphql/schema.gql > tests/test.schema.gql
|
||||
head -n -1 src/lib/graphql/schema.gql > tests/test.schema.gql
|
||||
PUBLIC_KEY=$(sed 's/$/\\n/' tests/public.key | tr -d '\n')
|
||||
echo "# Dgraph.Authorization {\"VerificationKey\":\"$PUBLIC_KEY\",\"Namespace\":\"https://dgraph.io/jwt/claims\",\"Header\":\"Authorization\",\"Algo\":\"RS256\"}" >> tests/test.schema.gql
|
||||
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
{
|
||||
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
|
||||
"extends": "@next-auth/tsconfig/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"baseUrl": ".",
|
||||
"isolatedModules": true,
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": ".",
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
"skipDefaultLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"stripInternal": true,
|
||||
"declarationMap": true,
|
||||
"declaration": true
|
||||
},
|
||||
"exclude": ["tests", "dist", "jest.config.js"]
|
||||
}
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.d.ts",
|
||||
]
|
||||
}
|
||||
@@ -8,14 +8,14 @@
|
||||
</a>
|
||||
<h3 align="center"><b>DynamoDB Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||
<p align="center" style="align: center;">
|
||||
<a href="https://npm.im/@next-auth/dynamodb-adapter">
|
||||
<a href="https://npm.im/@auth/dynamodb-adapter">
|
||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||
</a>
|
||||
<a href="https://npm.im/@next-auth/dynamodb-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/dynamodb-adapter?color=green&label=@next-auth/dynamodb-adapter&style=flat-square">
|
||||
<a href="https://npm.im/@auth/dynamodb-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@auth/dynamodb-adapter?color=green&label=@auth/dynamodb-adapter&style=flat-square">
|
||||
</a>
|
||||
<a href="https://www.npmtrends.com/@next-auth/dynamodb-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@next-auth/dynamodb-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||
<a href="https://www.npmtrends.com/@auth/dynamodb-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@auth/dynamodb-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,7 +1,7 @@
|
||||
{
|
||||
"name": "@next-auth/dynamodb-adapter",
|
||||
"name": "@auth/dynamodb-adapter",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"version": "3.0.2",
|
||||
"version": "1.0.0",
|
||||
"description": "AWS DynamoDB adapter for next-auth.",
|
||||
"keywords": [
|
||||
"next-auth",
|
||||
@@ -9,18 +9,10 @@
|
||||
"oauth",
|
||||
"dynamodb"
|
||||
],
|
||||
"type": "module",
|
||||
"types": "./index.d.ts",
|
||||
"homepage": "https://authjs.dev",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./index.js"
|
||||
}
|
||||
},
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -32,19 +24,27 @@
|
||||
"clean": "rm -rf index.*",
|
||||
"build": "pnpm clean && tsc"
|
||||
},
|
||||
"author": "Pol Marnette",
|
||||
"contributors": [
|
||||
"Balázs Orbán <info@balazsorban.com>"
|
||||
],
|
||||
"license": "ISC",
|
||||
"type": "module",
|
||||
"types": "./index.d.ts",
|
||||
"files": [
|
||||
"README.md",
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
"index.d.ts.map",
|
||||
"*.js",
|
||||
"*.d.ts*",
|
||||
"src"
|
||||
],
|
||||
"author": "Pol Marnette",
|
||||
"license": "ISC",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./index.js"
|
||||
}
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@aws-sdk/client-dynamodb": "^3.36.1",
|
||||
"@aws-sdk/lib-dynamodb": "^3.36.1",
|
||||
"next-auth": "^4"
|
||||
"@aws-sdk/lib-dynamodb": "^3.36.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aws-sdk/client-dynamodb": "^3.36.1",
|
||||
@@ -52,11 +52,9 @@
|
||||
"@next-auth/adapter-test": "workspace:*",
|
||||
"@next-auth/tsconfig": "workspace:*",
|
||||
"@shelf/jest-dynamodb": "^2.1.0",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"jest": "^27.4.3",
|
||||
"next-auth": "workspace:*"
|
||||
"jest": "^27.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": "^9.0.0"
|
||||
"@auth/core": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -9,12 +9,11 @@
|
||||
* ## Installation
|
||||
*
|
||||
* ```bash npm2yarn2pnpm
|
||||
* npm install next-auth @next-auth/dynamodb-adapter
|
||||
* npm install next-auth @auth/dynamodb-adapter
|
||||
* ```
|
||||
*
|
||||
* @module @next-auth/dynamodb-adapter
|
||||
* @module @auth/dynamodb-adapter
|
||||
*/
|
||||
import { v4 as uuid } from "uuid"
|
||||
|
||||
import type {
|
||||
BatchWriteCommandInput,
|
||||
@@ -26,7 +25,7 @@ import type {
|
||||
AdapterAccount,
|
||||
AdapterUser,
|
||||
VerificationToken,
|
||||
} from "next-auth/adapters"
|
||||
} from "@auth/core/adapters"
|
||||
|
||||
export interface DynamoDBAdapterOptions {
|
||||
tableName?: string
|
||||
@@ -53,7 +52,7 @@ export interface DynamoDBAdapterOptions {
|
||||
* import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
|
||||
* import NextAuth from "next-auth";
|
||||
* import Providers from "next-auth/providers";
|
||||
* import { DynamoDBAdapter } from "@next-auth/dynamodb-adapter"
|
||||
* import { DynamoDBAdapter } from "@auth/dynamodb-adapter"
|
||||
*
|
||||
* const config: DynamoDBClientConfig = {
|
||||
* credentials: {
|
||||
@@ -187,7 +186,7 @@ export function DynamoDBAdapter(
|
||||
async createUser(data) {
|
||||
const user: AdapterUser = {
|
||||
...(data as any),
|
||||
id: uuid(),
|
||||
id: crypto.randomUUID(),
|
||||
}
|
||||
|
||||
await client.put({
|
||||
@@ -312,7 +311,7 @@ export function DynamoDBAdapter(
|
||||
async linkAccount(data) {
|
||||
const item = {
|
||||
...data,
|
||||
id: uuid(),
|
||||
id: crypto.randomUUID(),
|
||||
[pk]: `USER#${data.userId}`,
|
||||
[sk]: `ACCOUNT#${data.provider}#${data.providerAccountId}`,
|
||||
[GSI1PK]: `ACCOUNT#${data.provider}`,
|
||||
@@ -376,7 +375,7 @@ export function DynamoDBAdapter(
|
||||
},
|
||||
async createSession(data) {
|
||||
const session = {
|
||||
id: uuid(),
|
||||
id: crypto.randomUUID(),
|
||||
...data,
|
||||
}
|
||||
await client.put({
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
{
|
||||
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
|
||||
"extends": "@next-auth/tsconfig/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": ".",
|
||||
"allowJs": true,
|
||||
"baseUrl": ".",
|
||||
"isolatedModules": true,
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": ".",
|
||||
"rootDir": "src",
|
||||
"skipDefaultLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"stripInternal": true,
|
||||
"declarationMap": true,
|
||||
"declaration": true
|
||||
},
|
||||
"exclude": ["tests", "dist", "jest.config.js", "jest-dynamodb-config.js"]
|
||||
}
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.d.ts",
|
||||
]
|
||||
}
|
||||
@@ -8,14 +8,14 @@
|
||||
</a>
|
||||
<h3 align="center"><b>MikroORM Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||
<p align="center" style="align: center;">
|
||||
<a href="https://npm.im/@next-auth/mikro-orm-adapter">
|
||||
<a href="https://npm.im/@auth/mikro-orm-adapter">
|
||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||
</a>
|
||||
<a href="https://npm.im/@next-auth/mikro-orm-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/mikro-orm-adapter?color=green&label=@next-auth/mikro-orm-adapter&style=flat-square">
|
||||
<a href="https://npm.im/@auth/mikro-orm-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@auth/mikro-orm-adapter?color=green&label=@auth/mikro-orm-adapter&style=flat-square">
|
||||
</a>
|
||||
<a href="https://www.npmtrends.com/@next-auth/mikro-orm-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@next-auth/mikro-orm-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||
<a href="https://www.npmtrends.com/@auth/mikro-orm-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@auth/mikro-orm-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,7 +1,7 @@
|
||||
{
|
||||
"name": "@next-auth/mikro-orm-adapter",
|
||||
"version": "3.0.1",
|
||||
"description": "MikroORM adapter for next-auth.",
|
||||
"name": "@auth/mikro-orm-adapter",
|
||||
"version": "1.0.0",
|
||||
"description": "MikroORM adapter for Auth.js",
|
||||
"homepage": "https://authjs.dev",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
@@ -11,7 +11,20 @@
|
||||
"contributors": [
|
||||
"Balázs Orbán <info@balazsorban.com>"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"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",
|
||||
@@ -27,27 +40,20 @@
|
||||
"test": "jest --runInBand",
|
||||
"build": "tsc"
|
||||
},
|
||||
"files": [
|
||||
"README.md",
|
||||
"dist"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@mikro-orm/core": "^5",
|
||||
"next-auth": "^4"
|
||||
"@mikro-orm/core": "^5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mikro-orm/core": "^5",
|
||||
"@mikro-orm/sqlite": "^5",
|
||||
"@next-auth/adapter-test": "workspace:*",
|
||||
"@next-auth/tsconfig": "workspace:*",
|
||||
"@types/uuid": ">=8",
|
||||
"jest": "^29",
|
||||
"next-auth": "workspace:*"
|
||||
"jest": "^29"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": "^9"
|
||||
"@auth/core": "workspace:*"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,10 +9,10 @@
|
||||
* ## Installation
|
||||
*
|
||||
* ```bash npm2yarn2pnpm
|
||||
* npm install next-auth @next-auth/dynamodb-adapter @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
|
||||
* npm install @mikro-orm/core @auth/mikro-orm-adapter
|
||||
* ```
|
||||
*
|
||||
* @module @next-auth/dynamodb-adapter
|
||||
* @module @auth/mikro-orm-adapter
|
||||
*/
|
||||
import type {
|
||||
Connection,
|
||||
@@ -20,11 +20,11 @@ import type {
|
||||
Options as ORMOptions,
|
||||
} from "@mikro-orm/core"
|
||||
|
||||
import type { Adapter } from "next-auth/adapters"
|
||||
import type { Adapter } from "@auth/core/adapters"
|
||||
|
||||
import { MikroORM, wrap } from "@mikro-orm/core"
|
||||
|
||||
import * as defaultEntities from "./entities"
|
||||
import * as defaultEntities from "./lib/entities"
|
||||
|
||||
export { defaultEntities }
|
||||
|
||||
@@ -35,7 +35,7 @@ export { defaultEntities }
|
||||
*
|
||||
* ```typescript title="pages/api/auth/[...nextauth].ts"
|
||||
* import NextAuth from "next-auth"
|
||||
* import { MikroOrmAdapter } from "@next-auth/mikro-orm-adapter"
|
||||
* import { MikroOrmAdapter } from "@auth/mikro-orm-adapter"
|
||||
*
|
||||
* export default NextAuth({
|
||||
* adapter: MikroOrmAdapter({
|
||||
@@ -67,7 +67,7 @@ export { defaultEntities }
|
||||
* Property,
|
||||
* Unique,
|
||||
* } from "@mikro-orm/core"
|
||||
* import { defaultEntities } from "@next-auth/mikro-orm-adapter"
|
||||
* import { defaultEntities } from "@auth/mikro-orm-adapter"
|
||||
*
|
||||
* const { Account, Session } = defaultEntities
|
||||
*
|
||||
@@ -124,7 +124,7 @@ export { defaultEntities }
|
||||
*
|
||||
* ```typescript title="config/mikro-orm.ts"
|
||||
* import { Options } from "@mikro-orm/core";
|
||||
* import { defaultEntities } from "@next-auth/mikro-orm-adapter"
|
||||
* import { defaultEntities } from "@auth/mikro-orm-adapter"
|
||||
*
|
||||
* const config: Options = {
|
||||
* ...
|
||||
@@ -186,7 +186,6 @@ export function MikroOrmAdapter<
|
||||
* Method used in testing. You won't need to call this in your app.
|
||||
* @internal
|
||||
*/
|
||||
// @ts-expect-error
|
||||
async __disconnect() {
|
||||
const em = await getEM()
|
||||
await em.getConnection().close()
|
||||
@@ -240,6 +239,7 @@ export function MikroOrmAdapter<
|
||||
|
||||
return wrap(user).toObject()
|
||||
},
|
||||
// @ts-expect-error
|
||||
async linkAccount(data) {
|
||||
const em = await getEM()
|
||||
const user = await em.findOne(UserModel, { id: data.userId })
|
||||
@@ -251,6 +251,7 @@ export function MikroOrmAdapter<
|
||||
|
||||
return wrap(account).toObject()
|
||||
},
|
||||
// @ts-expect-error
|
||||
async unlinkAccount(provider_providerAccountId) {
|
||||
const em = await getEM()
|
||||
const account = await em.findOne(AccountModel, {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { v4 as randomUUID } from "uuid"
|
||||
|
||||
import {
|
||||
Property,
|
||||
Unique,
|
||||
@@ -16,8 +14,7 @@ import type {
|
||||
AdapterAccount,
|
||||
AdapterSession,
|
||||
VerificationToken as AdapterVerificationToken,
|
||||
} from "next-auth/adapters"
|
||||
import type { ProviderType } from "next-auth/providers"
|
||||
} from "@auth/core/adapters"
|
||||
|
||||
type RemoveIndex<T> = {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
@@ -27,7 +24,7 @@ type RemoveIndex<T> = {
|
||||
@Entity()
|
||||
export class User implements RemoveIndex<AdapterUser> {
|
||||
@PrimaryKey()
|
||||
id: string = randomUUID()
|
||||
id: string = crypto.randomUUID()
|
||||
|
||||
@Property({ type: types.string, nullable: true })
|
||||
name?: string
|
||||
@@ -63,7 +60,7 @@ export class User implements RemoveIndex<AdapterUser> {
|
||||
export class Session implements AdapterSession {
|
||||
@PrimaryKey()
|
||||
@Property({ type: types.string })
|
||||
id: string = randomUUID()
|
||||
id: string = crypto.randomUUID()
|
||||
|
||||
@ManyToOne({
|
||||
entity: "User",
|
||||
@@ -88,7 +85,7 @@ export class Session implements AdapterSession {
|
||||
export class Account implements RemoveIndex<AdapterAccount> {
|
||||
@PrimaryKey()
|
||||
@Property({ type: types.string })
|
||||
id: string = randomUUID()
|
||||
id: string = crypto.randomUUID()
|
||||
|
||||
@ManyToOne({
|
||||
entity: "User",
|
||||
@@ -101,7 +98,7 @@ export class Account implements RemoveIndex<AdapterAccount> {
|
||||
userId!: string
|
||||
|
||||
@Property({ type: types.string })
|
||||
type!: ProviderType
|
||||
type!: AdapterAccount["type"]
|
||||
|
||||
@Property({ type: types.string })
|
||||
provider!: string
|
||||
@@ -13,13 +13,15 @@ import {
|
||||
Options,
|
||||
types,
|
||||
} from "@mikro-orm/core"
|
||||
import { randomUUID, runBasicTests } from "@next-auth/adapter-test"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
|
||||
globalThis.crypto ??= require("node:crypto").webcrypto
|
||||
|
||||
@Entity()
|
||||
export class User implements defaultEntities.User {
|
||||
@PrimaryKey()
|
||||
@Property({ type: types.string })
|
||||
id: string = randomUUID()
|
||||
id: string = crypto.randomUUID()
|
||||
|
||||
@Property({ type: types.string, nullable: true })
|
||||
name?: string
|
||||
@@ -60,7 +62,7 @@ export class User implements defaultEntities.User {
|
||||
export class VeryImportantEntity {
|
||||
@PrimaryKey()
|
||||
@Property({ type: types.string })
|
||||
id: string = randomUUID()
|
||||
id: string = crypto.randomUUID()
|
||||
|
||||
@Property({ type: types.boolean })
|
||||
important = true
|
||||
|
||||
@@ -1,13 +1,27 @@
|
||||
{
|
||||
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
|
||||
"extends": "@next-auth/tsconfig/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"esModuleInterop": true,
|
||||
"allowJs": true,
|
||||
"baseUrl": ".",
|
||||
"isolatedModules": true,
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": ".",
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"stripInternal": true
|
||||
"skipDefaultLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"stripInternal": true,
|
||||
"declarationMap": true,
|
||||
"declaration": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["dist", "test", "node_modules"]
|
||||
}
|
||||
"include": [
|
||||
"src/**/*",
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.d.ts",
|
||||
]
|
||||
}
|
||||
@@ -8,14 +8,14 @@
|
||||
</a>
|
||||
<h3 align="center"><b>MongoDB Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||
<p align="center" style="align: center;">
|
||||
<a href="https://npm.im/@next-auth/mongodb-adapter">
|
||||
<a href="https://npm.im/@auth/mongodb-adapter">
|
||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||
</a>
|
||||
<a href="https://npm.im/@next-auth/mongodb-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/mongodb-adapter?color=green&label=@next-auth/mongodb-adapter&style=flat-square">
|
||||
<a href="https://npm.im/@auth/mongodb-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@auth/mongodb-adapter?color=green&label=@auth/mongodb-adapter&style=flat-square">
|
||||
</a>
|
||||
<a href="https://www.npmtrends.com/@next-auth/mongodb-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@next-auth/mongodb-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||
<a href="https://www.npmtrends.com/@auth/mongodb-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@auth/mongodb-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,14 +1,26 @@
|
||||
{
|
||||
"name": "@next-auth/mongodb-adapter",
|
||||
"version": "1.1.3",
|
||||
"description": "mongoDB adapter for next-auth.",
|
||||
"name": "@auth/mongodb-adapter",
|
||||
"version": "1.0.0",
|
||||
"description": "MongoDB 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": "Balázs Orbán <info@balazsorban.com>",
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
"types": "./index.d.ts",
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.d.ts*",
|
||||
"src"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./index.js"
|
||||
}
|
||||
},
|
||||
"license": "ISC",
|
||||
"keywords": [
|
||||
"next-auth",
|
||||
@@ -26,20 +38,17 @@
|
||||
"test:watch": "./tests/test.sh -w",
|
||||
"build": "tsc"
|
||||
},
|
||||
"files": [
|
||||
"README.md",
|
||||
"dist"
|
||||
],
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"mongodb": "^5 || ^4",
|
||||
"next-auth": "^4"
|
||||
"mongodb": "^5 || ^4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:*",
|
||||
"@next-auth/tsconfig": "workspace:*",
|
||||
"jest": "^27.4.3",
|
||||
"mongodb": "^5.1.0",
|
||||
"next-auth": "workspace:*"
|
||||
"mongodb": "^5.1.0"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
* ## Installation
|
||||
*
|
||||
* ```bash npm2yarn2pnpm
|
||||
* npm install next-auth @next-auth/mongodb-adapter mongodb
|
||||
* npm install @auth/mongodb-adapter mongodb
|
||||
* ```
|
||||
*
|
||||
* @module @next-auth/mongodb-adapter
|
||||
* @module @auth/mongodb-adapter
|
||||
*/
|
||||
import { ObjectId } from "mongodb"
|
||||
|
||||
@@ -22,7 +22,7 @@ import type {
|
||||
AdapterAccount,
|
||||
AdapterSession,
|
||||
VerificationToken,
|
||||
} from "next-auth/adapters"
|
||||
} from "@auth/core/adapters"
|
||||
import type { MongoClient } from "mongodb"
|
||||
|
||||
/** This is the interface of the MongoDB adapter options. */
|
||||
@@ -132,7 +132,7 @@ export function _id(hex?: string) {
|
||||
*
|
||||
* ```js
|
||||
* import NextAuth from "next-auth"
|
||||
* import { MongoDBAdapter } from "@next-auth/mongodb-adapter"
|
||||
* import { MongoDBAdapter } from "@auth/mongodb-adapter"
|
||||
* import clientPromise from "../../../lib/mongodb"
|
||||
*
|
||||
* // For more information on each option (and a full list of options) go to
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
{
|
||||
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
|
||||
"extends": "@next-auth/tsconfig/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"baseUrl": ".",
|
||||
"isolatedModules": true,
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": ".",
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
"skipDefaultLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"stripInternal": true,
|
||||
"declarationMap": true,
|
||||
"declaration": true
|
||||
},
|
||||
"exclude": ["tests", "dist", "jest.config.js"]
|
||||
}
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.d.ts",
|
||||
]
|
||||
}
|
||||
@@ -8,14 +8,14 @@
|
||||
</a>
|
||||
<h3 align="center"><b>Prisma Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||
<p align="center" style="align: center;">
|
||||
<a href="https://npm.im/@next-auth/prisma-adapter">
|
||||
<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://npm.im/@next-auth/prisma-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/prisma-adapter?color=green&label=@next-auth/prisma-adapter&style=flat-square">
|
||||
<a href="https://npm.im/@auth/prisma-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@auth/prisma-adapter?color=green&label=@auth/prisma-adapter&style=flat-square">
|
||||
</a>
|
||||
<a href="https://www.npmtrends.com/@next-auth/prisma-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@next-auth/prisma-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||
<a href="https://www.npmtrends.com/@auth/prisma-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@auth/prisma-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,14 +1,29 @@
|
||||
{
|
||||
"name": "@next-auth/prisma-adapter",
|
||||
"version": "1.0.6",
|
||||
"description": "Prisma adapter for next-auth.",
|
||||
"homepage": "https://authjs.dev",
|
||||
"name": "@auth/prisma-adapter",
|
||||
"version": "1.0.0",
|
||||
"description": "Prisma adapter for Auth.js",
|
||||
"homepage": "https://authjs.dev/reference/adapter/prisma",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
"author": "William Luke",
|
||||
"main": "dist/index.js",
|
||||
"contributors": [
|
||||
"Balázs Orbán <info@balazsorban.com>"
|
||||
],
|
||||
"type": "module",
|
||||
"types": "./index.d.ts",
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.d.ts*",
|
||||
"src"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./index.js"
|
||||
}
|
||||
},
|
||||
"license": "ISC",
|
||||
"keywords": [
|
||||
"next-auth",
|
||||
@@ -32,22 +47,19 @@
|
||||
"dev": "prisma generate && tsc -w",
|
||||
"studio": "prisma studio"
|
||||
},
|
||||
"files": [
|
||||
"README.md",
|
||||
"dist"
|
||||
],
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@prisma/client": ">=2.26.0 || >=3",
|
||||
"next-auth": "^4"
|
||||
"@prisma/client": ">=2.26.0 || >=3 || >=4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:*",
|
||||
"@next-auth/tsconfig": "workspace:*",
|
||||
"@prisma/client": "^3.10.0",
|
||||
"@prisma/client": "^4.15.0",
|
||||
"jest": "^27.4.3",
|
||||
"mongodb": "^4.4.0",
|
||||
"next-auth": "workspace:*",
|
||||
"prisma": "^3.10.0"
|
||||
"prisma": "^4.15.0"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
* ## Installation
|
||||
*
|
||||
* ```bash npm2yarn2pnpm
|
||||
* npm install next-auth @prisma/client @next-auth/prisma-adapter
|
||||
* npm install @prisma/client @auth/prisma-adapter
|
||||
* npm install prisma --save-dev
|
||||
* ```
|
||||
*
|
||||
* @module @next-auth/prisma-adapter
|
||||
* @module @auth/prisma-adapter
|
||||
*/
|
||||
import type { PrismaClient, Prisma } from "@prisma/client"
|
||||
import type { Adapter, AdapterAccount } from "next-auth/adapters"
|
||||
import type { Adapter, AdapterAccount } from "@auth/core/adapters"
|
||||
|
||||
/**
|
||||
* ## Setup
|
||||
@@ -26,7 +26,7 @@ import type { Adapter, AdapterAccount } from "next-auth/adapters"
|
||||
* ```js title="pages/api/auth/[...nextauth].js"
|
||||
* import NextAuth from "next-auth"
|
||||
* import GoogleProvider from "next-auth/providers/google"
|
||||
* import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
* import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||
* import { PrismaClient } from "@prisma/client"
|
||||
*
|
||||
* const prisma = new PrismaClient()
|
||||
@@ -42,8 +42,6 @@ import type { Adapter, AdapterAccount } from "next-auth/adapters"
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* ## Advanced usage
|
||||
*
|
||||
* ### Create the Prisma schema from scratch
|
||||
*
|
||||
* You need to use at least Prisma 2.26.0. Create a schema file in `prisma/schema.prisma` similar to this one:
|
||||
|
||||
@@ -1,9 +1,25 @@
|
||||
{
|
||||
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
|
||||
"extends": "@next-auth/tsconfig/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"baseUrl": ".",
|
||||
"isolatedModules": true,
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": ".",
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
"skipDefaultLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"stripInternal": true,
|
||||
"declarationMap": true,
|
||||
"declaration": true
|
||||
},
|
||||
"include": ["."],
|
||||
"exclude": ["tests", "dist", "jest.config.js"]
|
||||
}
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.d.ts",
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Adapter } from "next-auth/adapters"
|
||||
import type { Adapter } from "@auth/core/adapters"
|
||||
import { createHash, randomUUID } from "crypto"
|
||||
|
||||
const requiredMethods = [
|
||||
@@ -58,7 +58,8 @@ export async function runBasicTests(options: TestOptions) {
|
||||
await options.db.connect?.()
|
||||
})
|
||||
|
||||
const { adapter, db, skipTests } = options
|
||||
const { adapter: _adapter, db, skipTests } = options
|
||||
const adapter = _adapter as Required<Adapter>
|
||||
|
||||
afterAll(async () => {
|
||||
// @ts-expect-error This is only used for the TypeORM adapter
|
||||
@@ -88,7 +89,7 @@ export async function runBasicTests(options: TestOptions) {
|
||||
providerAccountId: randomUUID(),
|
||||
type: "oauth",
|
||||
access_token: randomUUID(),
|
||||
expires_at: ONE_MONTH,
|
||||
expires_at: ONE_MONTH / 1000,
|
||||
id_token: randomUUID(),
|
||||
refresh_token: randomUUID(),
|
||||
token_type: "bearer",
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
"license": "ISC",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@auth/core": "workspace:*",
|
||||
"@babel/cli": "^7.14.3",
|
||||
"@babel/plugin-transform-runtime": "^7.14.3",
|
||||
"@babel/preset-env": "^7.14.2",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
"jest": "^27.0.3",
|
||||
"next-auth": "workspace:*",
|
||||
"ts-jest": "^27.0.3",
|
||||
"typescript": "^4.2.4"
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"stripInternal": true
|
||||
},
|
||||
"include": ["."],
|
||||
"exclude": ["tests", "dist", "jest.config.js"]
|
||||
}
|
||||
1
packages/adapter-typeorm/.npmrc
Normal file
1
packages/adapter-typeorm/.npmrc
Normal file
@@ -0,0 +1 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -8,14 +8,14 @@
|
||||
</a>
|
||||
<h3 align="center"><b>TypeORM Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||
<p align="center" style="align: center;">
|
||||
<a href="https://npm.im/@next-auth/typeorm-legacy-adapter">
|
||||
<a href="https://npm.im/@auth/typeorm-adapter">
|
||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||
</a>
|
||||
<a href="https://npm.im/@next-auth/typeorm-legacy-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/typeorm-legacy-adapter?color=green&label=@next-auth/typeorm-legacy-adapter&style=flat-square">
|
||||
<a href="https://npm.im/@auth/typeorm-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@auth/typeorm-adapter?color=green&label=@auth/typeorm-adapter&style=flat-square">
|
||||
</a>
|
||||
<a href="https://www.npmtrends.com/@next-auth/typeorm-legacy-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@next-auth/typeorm-legacy-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||
<a href="https://www.npmtrends.com/@auth/typeorm-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@auth/typeorm-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,8 +1,8 @@
|
||||
{
|
||||
"name": "@next-auth/typeorm-legacy-adapter",
|
||||
"version": "2.0.2",
|
||||
"description": "TypeORM (legacy) adapter for next-auth.",
|
||||
"homepage": "https://authjs.dev",
|
||||
"name": "@auth/typeorm-adapter",
|
||||
"version": "1.0.0",
|
||||
"description": "TypeORM adapter for Auth.js.",
|
||||
"homepage": "https://authjs.dev/reference/adapter/typeorm",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
@@ -11,11 +11,19 @@
|
||||
"contributors": [
|
||||
"Balázs Orbán <info@balazsorban.com>"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
"types": "./index.d.ts",
|
||||
"files": [
|
||||
"README.md",
|
||||
"dist"
|
||||
"*.js",
|
||||
"*.d.ts*",
|
||||
"src"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./index.js"
|
||||
}
|
||||
},
|
||||
"license": "ISC",
|
||||
"keywords": [
|
||||
"next-auth",
|
||||
@@ -38,26 +46,27 @@
|
||||
"test:containers": "tests/test.sh",
|
||||
"test": "tests/test.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:*",
|
||||
"@next-auth/tsconfig": "workspace:*",
|
||||
"jest": "^27.4.3",
|
||||
"mssql": "^7.2.1",
|
||||
"mysql": "^2.18.1",
|
||||
"next-auth": "workspace:*",
|
||||
"pg": "^8.7.3",
|
||||
"sqlite3": "^5.0.8",
|
||||
"typeorm": "0.3.7",
|
||||
"typeorm": "0.3.15",
|
||||
"typeorm-naming-strategies": "^4.1.0",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"mssql": "^6.2.1 || 7",
|
||||
"mysql": "^2.18.1",
|
||||
"next-auth": "^4",
|
||||
"pg": "^8.2.1",
|
||||
"sqlite3": "^5.0.2",
|
||||
"typeorm": "0.3.7"
|
||||
"typeorm": "^0.3.7"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"mysql": {
|
||||
@@ -9,17 +9,17 @@
|
||||
* ## Installation
|
||||
*
|
||||
* ```bash npm2yarn2pnpm
|
||||
* npm install next-auth @next-auth/typeorm-legacy-adapter typeorm
|
||||
* npm install @auth/typeorm-adapter typeorm
|
||||
* ```
|
||||
*
|
||||
* @module @next-auth/typeorm-legacy-adapter
|
||||
* @module @auth/typeorm-adapter
|
||||
*/
|
||||
import type {
|
||||
Adapter,
|
||||
AdapterUser,
|
||||
AdapterAccount,
|
||||
AdapterSession,
|
||||
} from "next-auth/adapters"
|
||||
} from "@auth/core/adapters"
|
||||
import { DataSourceOptions, DataSource, EntityManager } from "typeorm"
|
||||
import * as defaultEntities from "./entities"
|
||||
import { parseDataSourceConfig, updateConnectionEntities } from "./utils"
|
||||
@@ -29,7 +29,7 @@ export const entities = defaultEntities
|
||||
export type Entities = typeof entities
|
||||
|
||||
/** This is the interface for the TypeORM adapter options. */
|
||||
export interface TypeORMLegacyAdapterOptions {
|
||||
export interface TypeORMAdapterOptions {
|
||||
/**
|
||||
* The {@link https://orkhan.gitbook.io/typeorm/docs/entities TypeORM entities} to create the database tables from.
|
||||
*/
|
||||
@@ -70,16 +70,16 @@ export async function getManager(options: {
|
||||
*
|
||||
* ```javascript title="pages/api/auth/[...nextauth].js"
|
||||
* import NextAuth from "next-auth"
|
||||
* import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
* import { TypeORMAdapter } from "@auth/typeorm-adapter"
|
||||
*
|
||||
*
|
||||
* export default NextAuth({
|
||||
* adapter: TypeORMLegacyAdapter("yourconnectionstring"),
|
||||
* adapter: TypeORMAdapter("yourconnectionstring"),
|
||||
* ...
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* `TypeORMLegacyAdapter` takes either a connection string, or a [`ConnectionOptions`](https://github.com/typeorm/typeorm/blob/master/docs/connection-options.md) object as its first parameter.
|
||||
* `TypeORMAdapter` takes either a connection string, or a [`ConnectionOptions`](https://github.com/typeorm/typeorm/blob/master/docs/connection-options.md) object as its first parameter.
|
||||
*
|
||||
* ## Advanced usage
|
||||
*
|
||||
@@ -93,7 +93,7 @@ export async function getManager(options: {
|
||||
*
|
||||
* 1. Create a file containing your modified entities:
|
||||
*
|
||||
* (The file below is based on the [default entities](https://github.com/nextauthjs/next-auth/blob/main/packages/adapter-typeorm-legacy/src/entities.ts))
|
||||
* (The file below is based on the [default entities](https://github.com/nextauthjs/next-auth/blob/main/packages/adapter-typeorm/src/entities.ts))
|
||||
*
|
||||
* ```diff title="lib/entities.ts"
|
||||
* import {
|
||||
@@ -231,15 +231,15 @@ export async function getManager(options: {
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* 2. Pass them to `TypeORMLegacyAdapter`
|
||||
* 2. Pass them to `TypeORMAdapter`
|
||||
*
|
||||
* ```javascript title="pages/api/auth/[...nextauth].js"
|
||||
* import NextAuth from "next-auth"
|
||||
* import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
* import { TypeORMAdapter } from "@auth/typeorm-adapter"
|
||||
* import * as entities from "lib/entities"
|
||||
*
|
||||
* export default NextAuth({
|
||||
* adapter: TypeORMLegacyAdapter("yourconnectionstring", { entities }),
|
||||
* adapter: TypeORMAdapter("yourconnectionstring", { entities }),
|
||||
* ...
|
||||
* })
|
||||
* ```
|
||||
@@ -260,7 +260,7 @@ export async function getManager(options: {
|
||||
*
|
||||
* ```javascript title="pages/api/auth/[...nextauth].js"
|
||||
* import NextAuth from "next-auth"
|
||||
* import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
* import { TypeORMAdapter } from "@auth/typeorm-adapter"
|
||||
* import { SnakeNamingStrategy } from 'typeorm-naming-strategies'
|
||||
* import { ConnectionOptions } from "typeorm"
|
||||
*
|
||||
@@ -275,14 +275,14 @@ export async function getManager(options: {
|
||||
* }
|
||||
*
|
||||
* export default NextAuth({
|
||||
* adapter: TypeORMLegacyAdapter(connection),
|
||||
* adapter: TypeORMAdapter(connection),
|
||||
* ...
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export function TypeORMLegacyAdapter(
|
||||
export function TypeORMAdapter(
|
||||
dataSource: string | DataSourceOptions,
|
||||
options?: TypeORMLegacyAdapterOptions
|
||||
options?: TypeORMAdapterOptions
|
||||
): Adapter {
|
||||
const entities = options?.entities
|
||||
const c = {
|
||||
@@ -328,8 +328,10 @@ export function TypeORMLegacyAdapter(
|
||||
},
|
||||
async getUserByAccount(provider_providerAccountId) {
|
||||
const m = await getManager(c)
|
||||
// @ts-expect-error
|
||||
const account = await m.findOne<AdapterAccount & { user: AdapterUser }>(
|
||||
"AccountEntity",
|
||||
// @ts-expect-error
|
||||
{ where: provider_providerAccountId, relations: ["user"] }
|
||||
)
|
||||
if (!account) return null
|
||||
@@ -1,5 +1,5 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { TypeORMLegacyAdapter } from "../../src"
|
||||
import { TypeORMAdapter } from "../../src"
|
||||
import * as entities from "../custom-entities"
|
||||
import { db } from "../helpers"
|
||||
import { SnakeNamingStrategy } from "typeorm-naming-strategies"
|
||||
@@ -18,7 +18,7 @@ const mysqlConfig: ConnectionOptions = {
|
||||
}
|
||||
|
||||
runBasicTests({
|
||||
adapter: TypeORMLegacyAdapter(mysqlConfig, {
|
||||
adapter: TypeORMAdapter(mysqlConfig, {
|
||||
entities,
|
||||
}),
|
||||
db: db(mysqlConfig, entities),
|
||||
@@ -1,5 +1,5 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { TypeORMLegacyAdapter } from "../../src"
|
||||
import { TypeORMAdapter } from "../../src"
|
||||
import { db } from "../helpers"
|
||||
|
||||
const mysqlConfig = {
|
||||
@@ -13,6 +13,6 @@ const mysqlConfig = {
|
||||
}
|
||||
|
||||
runBasicTests({
|
||||
adapter: TypeORMLegacyAdapter(mysqlConfig),
|
||||
adapter: TypeORMAdapter(mysqlConfig),
|
||||
db: db(mysqlConfig),
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { TypeORMLegacyAdapter } from "../../src"
|
||||
import { TypeORMAdapter } from "../../src"
|
||||
import * as entities from "../custom-entities"
|
||||
import { db } from "../helpers"
|
||||
|
||||
@@ -7,7 +7,7 @@ const postgresConfig =
|
||||
"postgres://nextauth:password@localhost:5432/nextauth?synchronize=true"
|
||||
|
||||
runBasicTests({
|
||||
adapter: TypeORMLegacyAdapter(postgresConfig, {
|
||||
adapter: TypeORMAdapter(postgresConfig, {
|
||||
entities,
|
||||
}),
|
||||
db: db(postgresConfig, entities),
|
||||
@@ -1,11 +1,11 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { TypeORMLegacyAdapter } from "../../src"
|
||||
import { TypeORMAdapter } from "../../src"
|
||||
import { db } from "../helpers"
|
||||
|
||||
const postgresConfig =
|
||||
"postgres://nextauth:password@localhost:5432/nextauth?synchronize=true"
|
||||
|
||||
runBasicTests({
|
||||
adapter: TypeORMLegacyAdapter(postgresConfig),
|
||||
adapter: TypeORMAdapter(postgresConfig),
|
||||
db: db(postgresConfig),
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { TypeORMLegacyAdapter } from "../../src"
|
||||
import { TypeORMAdapter } from "../../src"
|
||||
import * as entities from "../custom-entities"
|
||||
import { db } from "../helpers"
|
||||
|
||||
@@ -11,7 +11,7 @@ const sqliteConfig = {
|
||||
}
|
||||
|
||||
runBasicTests({
|
||||
adapter: TypeORMLegacyAdapter(sqliteConfig, {
|
||||
adapter: TypeORMAdapter(sqliteConfig, {
|
||||
entities,
|
||||
}),
|
||||
db: db(sqliteConfig, entities),
|
||||
@@ -1,5 +1,5 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { TypeORMLegacyAdapter } from "../../src"
|
||||
import { TypeORMAdapter } from "../../src"
|
||||
import { db } from "../helpers"
|
||||
import { SnakeNamingStrategy } from "typeorm-naming-strategies"
|
||||
|
||||
@@ -14,6 +14,6 @@ const sqliteConfig: DataSourceOptions = {
|
||||
}
|
||||
|
||||
runBasicTests({
|
||||
adapter: TypeORMLegacyAdapter(sqliteConfig),
|
||||
adapter: TypeORMAdapter(sqliteConfig),
|
||||
db: db(sqliteConfig),
|
||||
})
|
||||
27
packages/adapter-typeorm/tsconfig.json
Normal file
27
packages/adapter-typeorm/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"extends": "@next-auth/tsconfig/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"baseUrl": ".",
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"isolatedModules": true,
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": ".",
|
||||
"rootDir": "src",
|
||||
"skipDefaultLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"stripInternal": true,
|
||||
"declarationMap": true,
|
||||
"declaration": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.d.ts",
|
||||
]
|
||||
}
|
||||
1
packages/adapter-upstash-redis/.npmrc
Normal file
1
packages/adapter-upstash-redis/.npmrc
Normal file
@@ -0,0 +1 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -8,14 +8,14 @@
|
||||
</a>
|
||||
<h3 align="center"><b>Upstash Redis Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||
<p align="center" style="align: center;">
|
||||
<a href="https://npm.im/@next-auth/upstash-redis-adapter">
|
||||
<a href="https://npm.im/@auth/upstash-redis-adapter">
|
||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||
</a>
|
||||
<a href="https://npm.im/@next-auth/upstash-redis-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/upstash-redis-adapter?color=green&label=@next-auth/upstash-redis-adapter&style=flat-square">
|
||||
<a href="https://npm.im/@auth/upstash-redis-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@auth/upstash-redis-adapter?color=green&label=@auth/upstash-redis-adapter&style=flat-square">
|
||||
</a>
|
||||
<a href="https://www.npmtrends.com/@next-auth/upstash-redis-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@next-auth/upstash-redis-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||
<a href="https://www.npmtrends.com/@auth/upstash-redis-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@auth/upstash-redis-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,14 +1,26 @@
|
||||
{
|
||||
"name": "@next-auth/upstash-redis-adapter",
|
||||
"version": "3.0.4",
|
||||
"description": "Upstash adapter for next-auth. It uses Upstash's connectionless (HTTP based) Redis client.",
|
||||
"name": "@auth/upstash-redis-adapter",
|
||||
"version": "1.0.0",
|
||||
"description": "Upstash 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": "github.com/kay-is",
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
"types": "./index.d.ts",
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.d.ts*",
|
||||
"src"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./index.js"
|
||||
}
|
||||
},
|
||||
"license": "ISC",
|
||||
"keywords": [
|
||||
"next-auth",
|
||||
@@ -25,13 +37,11 @@
|
||||
"test": "jest",
|
||||
"build": "tsc"
|
||||
},
|
||||
"files": [
|
||||
"README.md",
|
||||
"dist"
|
||||
],
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@upstash/redis": "^1.0.1",
|
||||
"next-auth": "^4"
|
||||
"@upstash/redis": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:*",
|
||||
@@ -43,9 +53,6 @@
|
||||
"jest": "^27.4.3",
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
* ## Installation
|
||||
*
|
||||
* ```bash npm2yarn2pnpm
|
||||
* npm install @upstash/redis @next-auth/upstash-redis-adapter
|
||||
* npm install @upstash/redis @auth/upstash-redis-adapter
|
||||
* ```
|
||||
*
|
||||
* @module @next-auth/upstash-redis-adapter
|
||||
* @module @auth/upstash-redis-adapter
|
||||
*/
|
||||
import type {
|
||||
Adapter,
|
||||
@@ -20,11 +20,9 @@ import type {
|
||||
AdapterAccount,
|
||||
AdapterSession,
|
||||
VerificationToken,
|
||||
} from "next-auth/adapters"
|
||||
} from "@auth/core/adapters"
|
||||
import type { Redis } from "@upstash/redis"
|
||||
|
||||
import { v4 as uuid } from "uuid"
|
||||
|
||||
/** This is the interface of the Upstash Redis adapter options. */
|
||||
export interface UpstashRedisAdapterOptions {
|
||||
/**
|
||||
@@ -93,7 +91,7 @@ export function hydrateDates(json: object) {
|
||||
* ```javascript title="pages/api/auth/[...nextauth].js"
|
||||
* import NextAuth from "next-auth"
|
||||
* import GoogleProvider from "next-auth/providers/google"
|
||||
* import { UpstashRedisAdapter } from "@next-auth/upstash-redis-adapter"
|
||||
* import { UpstashRedisAdapter } from "@auth/upstash-redis-adapter"
|
||||
* import upstashRedisClient from "@upstash/redis"
|
||||
*
|
||||
* const redis = upstashRedisClient(
|
||||
@@ -217,7 +215,7 @@ export function UpstashRedisAdapter(
|
||||
|
||||
return {
|
||||
async createUser(user) {
|
||||
const id = uuid()
|
||||
const id = crypto.randomUUID()
|
||||
// TypeScript thinks the emailVerified field is missing
|
||||
// but all fields are copied directly from user, so it's there
|
||||
return await setUser(id, { ...user, id })
|
||||
|
||||
@@ -4,6 +4,8 @@ import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import { hydrateDates, UpstashRedisAdapter } from "../src"
|
||||
import "dotenv/config"
|
||||
|
||||
globalThis.crypto ??= require("node:crypto").webcrypto
|
||||
|
||||
if (!process.env.UPSTASH_REDIS_URL || !process.env.UPSTASH_REDIS_KEY) {
|
||||
test("Skipping UpstashRedisAdapter tests, since required environment variables aren't available", () => {
|
||||
expect(true).toBe(true)
|
||||
@@ -27,6 +29,7 @@ const client = new Redis({
|
||||
runBasicTests({
|
||||
adapter: UpstashRedisAdapter(client, { baseKeyPrefix: "testApp:" }),
|
||||
db: {
|
||||
disconnect: client.flushdb,
|
||||
async user(id: string) {
|
||||
const data = await client.get<object>(`testApp:user:${id}`)
|
||||
if (!data) return null
|
||||
@@ -48,7 +51,7 @@ runBasicTests({
|
||||
},
|
||||
async verificationToken(where) {
|
||||
const data = await client.get<object>(
|
||||
`testApp:user:token:${where.identifier}`
|
||||
`testApp:user:token:${where.identifier}:${where.token}`
|
||||
)
|
||||
if (!data) return null
|
||||
return hydrateDates(data)
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
{
|
||||
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
|
||||
"extends": "@next-auth/tsconfig/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"baseUrl": ".",
|
||||
"isolatedModules": true,
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": ".",
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
"skipDefaultLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"stripInternal": true,
|
||||
"declarationMap": true,
|
||||
"declaration": true
|
||||
},
|
||||
"exclude": ["tests", "dist", "jest.config.js"]
|
||||
}
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.d.ts",
|
||||
]
|
||||
}
|
||||
@@ -195,7 +195,7 @@ import type { XataClient } from "./xata"
|
||||
* xata init --schema=./path/to/your/schema.json
|
||||
* ```
|
||||
*
|
||||
* The CLI will walk you through a setup process where you choose a [workspace](https://docs.xata.io/concepts/workspaces) (kind of like a GitHub org or a Vercel team) and an appropriate database. We recommend using a fresh database for this, as we'll augment it with tables that Auth.js needs.
|
||||
* The CLI will walk you through a setup process where you choose a [workspace](https://xata.io/docs/api-reference/workspaces) (kind of like a GitHub org or a Vercel team) and an appropriate database. We recommend using a fresh database for this, as we'll augment it with tables that Auth.js needs.
|
||||
*
|
||||
* Once you're done, you can continue using Auth.js in your project as expected, like creating a `./pages/api/auth/[...nextauth]` route.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@auth/core",
|
||||
"version": "0.7.1",
|
||||
"version": "0.8.2",
|
||||
"description": "Authentication for the Web.",
|
||||
"keywords": [
|
||||
"authentication",
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
*
|
||||
* ```ts title=my-adapter.ts
|
||||
* import { type Adapter } from "@auth/core/adapters"
|
||||
* import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
* import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||
* import { PrismaClient } from "@prisma/client"
|
||||
*
|
||||
* const prisma = new PrismaClient()
|
||||
@@ -228,6 +228,10 @@ export interface Adapter {
|
||||
deleteUser?(
|
||||
userId: string
|
||||
): Promise<void> | Awaitable<AdapterUser | null | undefined>
|
||||
/**
|
||||
* This method is invoked internally (but optionally can be used for manual linking).
|
||||
* It creates an [Account](https://authjs.dev/reference/adapters#models) in the database.
|
||||
*/
|
||||
linkAccount?(
|
||||
account: AdapterAccount
|
||||
): Promise<void> | Awaitable<AdapterAccount | null | undefined>
|
||||
|
||||
@@ -20,13 +20,6 @@ export class AuthError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo
|
||||
* Thrown when an Email address is already associated with an account
|
||||
* but the user is trying an OAuth account that is not linked to it.
|
||||
*/
|
||||
export class AccountNotLinked extends AuthError {}
|
||||
|
||||
/**
|
||||
* @todo
|
||||
* One of the database `Adapter` methods failed.
|
||||
@@ -37,8 +30,8 @@ export class AdapterError extends AuthError {}
|
||||
export class AuthorizedCallbackError extends AuthError {}
|
||||
|
||||
/**
|
||||
* There was an error while trying to finish up authenticating the user.
|
||||
* Depending on the type of provider, this could be for multiple reasons.
|
||||
* This error occurs when the user cannot finish the sign-in process.
|
||||
* Depending on the provider type, this could have happened for multiple reasons.
|
||||
*
|
||||
* :::tip
|
||||
* Check out `[auth][details]` in the error message to know which provider failed.
|
||||
@@ -48,7 +41,7 @@ export class AuthorizedCallbackError extends AuthError {}
|
||||
* ```
|
||||
* :::
|
||||
*
|
||||
* For an **OAuth provider**, possible causes are:
|
||||
* For an [OAuth provider](https://authjs.dev/reference/core/providers_oauth), possible causes are:
|
||||
* - The user denied access to the application
|
||||
* - There was an error parsing the OAuth Profile:
|
||||
* Check out the provider's `profile` or `userinfo.request` method to make sure
|
||||
@@ -56,7 +49,7 @@ export class AuthorizedCallbackError extends AuthError {}
|
||||
* - The `signIn` or `jwt` callback methods threw an uncaught error:
|
||||
* Check the callback method implementations.
|
||||
*
|
||||
* For an **Email provider**, possible causes are:
|
||||
* For an [Email provider](https://authjs.dev/reference/core/providers_email), possible causes are:
|
||||
* - The provided email/token combination was invalid/missing:
|
||||
* Check if the provider's `sendVerificationRequest` method correctly sends the email.
|
||||
* - The provided email/token combination has expired:
|
||||
@@ -64,7 +57,7 @@ export class AuthorizedCallbackError extends AuthError {}
|
||||
* - There was an error with the database:
|
||||
* Check the database logs.
|
||||
*
|
||||
* For a **Credentials provider**, possible causes are:
|
||||
* For a [Credentials provider](https://authjs.dev/reference/core/providers_credentials), possible causes are:
|
||||
* - The `authorize` method threw an uncaught error:
|
||||
* Check the provider's `authorize` method.
|
||||
* - The `signIn` or `jwt` callback methods threw an uncaught error:
|
||||
@@ -107,31 +100,87 @@ export class MissingAPIRoute extends AuthError {}
|
||||
/** @todo */
|
||||
export class MissingAuthorize extends AuthError {}
|
||||
|
||||
/** @todo */
|
||||
/**
|
||||
* Auth.js requires a secret to be set, but none was not found. This is used to encrypt cookies, JWTs and other sensitive data.
|
||||
*
|
||||
* :::note
|
||||
* If you are using a framework like Next.js, we try to automatically infer the secret from the `AUTH_SECRET` environment variable.
|
||||
* Alternatively, you can also explicitly set the [`AuthConfig.secret`](https://authjs.dev/reference/core#secret).
|
||||
* :::
|
||||
*
|
||||
*
|
||||
* :::tip
|
||||
* You can generate a good secret value:
|
||||
* - On Unix systems: type `openssl rand -hex 32` in the terminal
|
||||
* - Or generate one [online](https://generate-secret.vercel.app/32)
|
||||
*
|
||||
* :::
|
||||
*/
|
||||
export class MissingSecret extends AuthError {}
|
||||
|
||||
/** @todo */
|
||||
export class OAuthSignInError extends AuthError {}
|
||||
/**
|
||||
* @todo
|
||||
* Thrown when an Email address is already associated with an account
|
||||
* but the user is trying an OAuth account that is not linked to it.
|
||||
*/
|
||||
export class OAuthAccountNotLinked extends AuthError {}
|
||||
|
||||
/** @todo */
|
||||
/**
|
||||
* Thrown when an OAuth provider returns an error during the sign in process.
|
||||
* This could happen for example if the user denied access to the application or there was a configuration error.
|
||||
*
|
||||
* For a full list of possible reasons, check out the specification [Authorization Code Grant: Error Response](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1)
|
||||
*/
|
||||
export class OAuthCallbackError extends AuthError {}
|
||||
|
||||
/** @todo */
|
||||
export class OAuthCreateUserError extends AuthError {}
|
||||
|
||||
/** @todo */
|
||||
/**
|
||||
* This error occurs during an OAuth sign in attempt when the provdier's
|
||||
* response could not be parsed. This could for example happen if the provider's API
|
||||
* changed, or the [`OAuth2Config.profile`](https://authjs.dev/reference/core/providers_oauth#profile) method is not implemented correctly.
|
||||
*/
|
||||
export class OAuthProfileParseError extends AuthError {}
|
||||
|
||||
/** @todo */
|
||||
export class SessionTokenError extends AuthError {}
|
||||
|
||||
/** @todo */
|
||||
/**
|
||||
* This error occurs when the user cannot initiate the sign-in process.
|
||||
* Depending on the provider type, this could have happened for multiple reasons.
|
||||
*
|
||||
* :::tip
|
||||
* Check out `[auth][details]` in the error message to know which provider failed.
|
||||
* @example
|
||||
* ```sh
|
||||
* [auth][details]: { "provider": "github" }
|
||||
* ```
|
||||
* :::
|
||||
*
|
||||
* For an [OAuth provider](https://authjs.dev/reference/core/providers_oauth), possible causes are:
|
||||
* - The Authorization Server is not compliant with the [OAuth 2.0 specifcation](https://www.ietf.org/rfc/rfc6749.html)
|
||||
* Check the details in the error message.
|
||||
* - A runtime error occurred in Auth.js. This should be reported as a bug.
|
||||
*
|
||||
* For an [Email provider](https://authjs.dev/reference/core/providers_email), possible causes are:
|
||||
* - The email sent from the client is invalid, could not be normalized by [`EmailConfig.normalizeIdentifier`](https://authjs.dev/reference/core/providers_email#normalizeidentifier)
|
||||
* - The provided email/token combination has expired:
|
||||
* Ask the user to log in again.
|
||||
* - There was an error with the database:
|
||||
* Check the database logs.
|
||||
*
|
||||
*/
|
||||
export class SignInError extends AuthError {}
|
||||
|
||||
/** @todo */
|
||||
export class SignOutError extends AuthError {}
|
||||
|
||||
/** @todo */
|
||||
/**
|
||||
* Auth.js was requested to handle an operation that it does not support.
|
||||
*
|
||||
* See [`AuthAction`](https://authjs.dev/reference/core/types#authaction) for the supported actions.
|
||||
*/
|
||||
export class UnknownAction extends AuthError {}
|
||||
|
||||
/** @todo */
|
||||
|
||||
@@ -190,7 +190,7 @@ export interface JWTEncodeParams<Payload = JWT> {
|
||||
/**
|
||||
* The maximum age of the Auth.js issued JWT in seconds.
|
||||
*
|
||||
* @default 30 * 24 * 30 * 60 // 30 days
|
||||
* @default 30 * 24 * 60 * 60 // 30 days
|
||||
*/
|
||||
maxAge?: number
|
||||
}
|
||||
@@ -213,7 +213,7 @@ export interface JWTOptions {
|
||||
/**
|
||||
* The maximum age of the Auth.js issued JWT in seconds.
|
||||
*
|
||||
* @default 30 * 24 * 30 * 60 // 30 days
|
||||
* @default 30 * 24 * 60 * 60 // 30 days
|
||||
*/
|
||||
maxAge: number
|
||||
/** Override this method to control the Auth.js issued JWT encoding. */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AccountNotLinked } from "../errors.js"
|
||||
import { OAuthAccountNotLinked } from "../errors.js"
|
||||
import { fromDate } from "./utils/date.js"
|
||||
|
||||
import type {
|
||||
@@ -49,7 +49,7 @@ export async function handleLogin(
|
||||
}
|
||||
|
||||
const profile = _profile as AdapterUser
|
||||
const account = _account as AdapterAccount
|
||||
let account = _account as AdapterAccount
|
||||
|
||||
const {
|
||||
createUser,
|
||||
@@ -122,113 +122,116 @@ export async function handleLogin(
|
||||
})
|
||||
|
||||
return { session, user, isNewUser }
|
||||
} else if (account.type === "oauth" || account.type === "oidc") {
|
||||
// If signing in with OAuth account, check to see if the account exists already
|
||||
const userByAccount = await getUserByAccount({
|
||||
providerAccountId: account.providerAccountId,
|
||||
provider: account.provider,
|
||||
})
|
||||
if (userByAccount) {
|
||||
if (user) {
|
||||
// If the user is already signed in with this account, we don't need to do anything
|
||||
if (userByAccount.id === user.id) {
|
||||
return { session, user, isNewUser }
|
||||
}
|
||||
// If the user is currently signed in, but the new account they are signing in
|
||||
// with is already associated with another user, then we cannot link them
|
||||
// and need to return an error.
|
||||
throw new AccountNotLinked(
|
||||
"The account is already associated with another user",
|
||||
{ provider: account.provider }
|
||||
)
|
||||
}
|
||||
// If there is no active session, but the account being signed in with is already
|
||||
// associated with a valid user then create session to sign the user in.
|
||||
session = useJwtSession
|
||||
? {}
|
||||
: await createSession({
|
||||
sessionToken: generateSessionToken(),
|
||||
userId: userByAccount.id,
|
||||
expires: fromDate(options.session.maxAge),
|
||||
})
|
||||
}
|
||||
|
||||
return { session, user: userByAccount, isNewUser }
|
||||
} else {
|
||||
if (user) {
|
||||
// If the user is already signed in and the OAuth account isn't already associated
|
||||
// with another user account then we can go ahead and link the accounts safely.
|
||||
await linkAccount({ ...account, userId: user.id })
|
||||
await events.linkAccount?.({ user, account, profile })
|
||||
|
||||
// As they are already signed in, we don't need to do anything after linking them
|
||||
// If signing in with OAuth account, check to see if the account exists already
|
||||
const userByAccount = await getUserByAccount({
|
||||
providerAccountId: account.providerAccountId,
|
||||
provider: account.provider,
|
||||
})
|
||||
if (userByAccount) {
|
||||
if (user) {
|
||||
// If the user is already signed in with this account, we don't need to do anything
|
||||
if (userByAccount.id === user.id) {
|
||||
return { session, user, isNewUser }
|
||||
}
|
||||
// If the user is currently signed in, but the new account they are signing in
|
||||
// with is already associated with another user, then we cannot link them
|
||||
// and need to return an error.
|
||||
throw new OAuthAccountNotLinked(
|
||||
"The account is already associated with another user",
|
||||
{ provider: account.provider }
|
||||
)
|
||||
}
|
||||
// If there is no active session, but the account being signed in with is already
|
||||
// associated with a valid user then create session to sign the user in.
|
||||
session = useJwtSession
|
||||
? {}
|
||||
: await createSession({
|
||||
sessionToken: generateSessionToken(),
|
||||
userId: userByAccount.id,
|
||||
expires: fromDate(options.session.maxAge),
|
||||
})
|
||||
|
||||
// If the user is not signed in and it looks like a new OAuth account then we
|
||||
// check there also isn't an user account already associated with the same
|
||||
// email address as the one in the OAuth profile.
|
||||
//
|
||||
// This step is often overlooked in OAuth implementations, but covers the following cases:
|
||||
//
|
||||
// 1. It makes it harder for someone to accidentally create two accounts.
|
||||
// e.g. by signin in with email, then again with an oauth account connected to the same email.
|
||||
// 2. It makes it harder to hijack a user account using a 3rd party OAuth account.
|
||||
// e.g. by creating an oauth account then changing the email address associated with it.
|
||||
//
|
||||
// It's quite common for services to automatically link accounts in this case, but it's
|
||||
// better practice to require the user to sign in *then* link accounts to be sure
|
||||
// someone is not exploiting a problem with a third party OAuth service.
|
||||
//
|
||||
// OAuth providers should require email address verification to prevent this, but in
|
||||
// practice that is not always the case; this helps protect against that.
|
||||
const userByEmail = profile.email
|
||||
? await getUserByEmail(profile.email)
|
||||
: null
|
||||
if (userByEmail) {
|
||||
const provider = options.provider as OAuthConfig<any>
|
||||
if (provider?.allowDangerousEmailAccountLinking) {
|
||||
// If you trust the oauth provider to correctly verify email addresses, you can opt-in to
|
||||
// account linking even when the user is not signed-in.
|
||||
user = userByEmail
|
||||
} else {
|
||||
// We end up here when we don't have an account with the same [provider].id *BUT*
|
||||
// we do already have an account with the same email address as the one in the
|
||||
// OAuth profile the user has just tried to sign in with.
|
||||
//
|
||||
// We don't want to have two accounts with the same email address, and we don't
|
||||
// want to link them in case it's not safe to do so, so instead we prompt the user
|
||||
// to sign in via email to verify their identity and then link the accounts.
|
||||
throw new AccountNotLinked(
|
||||
"Another account already exists with the same e-mail address",
|
||||
{ provider: account.provider }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// If the current user is not logged in and the profile isn't linked to any user
|
||||
// accounts (by email or provider account id)...
|
||||
//
|
||||
// If no account matching the same [provider].id or .email exists, we can
|
||||
// create a new account for the user, link it to the OAuth account and
|
||||
// create a new session for them so they are signed in with it.
|
||||
const { id: _, ...newUser } = { ...profile, emailVerified: null }
|
||||
user = await createUser(newUser)
|
||||
}
|
||||
await events.createUser?.({ user })
|
||||
return { session, user: userByAccount, isNewUser }
|
||||
} else {
|
||||
const { provider: p } = options as InternalOptions<"oauth" | "oidc">
|
||||
const { type, provider, providerAccountId, userId, ...tokenSet } = account
|
||||
const defaults = { providerAccountId, provider, type, userId }
|
||||
account = Object.assign(p.account(tokenSet) ?? {}, defaults)
|
||||
|
||||
if (user) {
|
||||
// If the user is already signed in and the OAuth account isn't already associated
|
||||
// with another user account then we can go ahead and link the accounts safely.
|
||||
await linkAccount({ ...account, userId: user.id })
|
||||
await events.linkAccount?.({ user, account, profile })
|
||||
|
||||
session = useJwtSession
|
||||
? {}
|
||||
: await createSession({
|
||||
sessionToken: generateSessionToken(),
|
||||
userId: user.id,
|
||||
expires: fromDate(options.session.maxAge),
|
||||
})
|
||||
|
||||
return { session, user, isNewUser: true }
|
||||
// As they are already signed in, we don't need to do anything after linking them
|
||||
return { session, user, isNewUser }
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error("Unsupported account type")
|
||||
// If the user is not signed in and it looks like a new OAuth account then we
|
||||
// check there also isn't an user account already associated with the same
|
||||
// email address as the one in the OAuth profile.
|
||||
//
|
||||
// This step is often overlooked in OAuth implementations, but covers the following cases:
|
||||
//
|
||||
// 1. It makes it harder for someone to accidentally create two accounts.
|
||||
// e.g. by signin in with email, then again with an oauth account connected to the same email.
|
||||
// 2. It makes it harder to hijack a user account using a 3rd party OAuth account.
|
||||
// e.g. by creating an oauth account then changing the email address associated with it.
|
||||
//
|
||||
// It's quite common for services to automatically link accounts in this case, but it's
|
||||
// better practice to require the user to sign in *then* link accounts to be sure
|
||||
// someone is not exploiting a problem with a third party OAuth service.
|
||||
//
|
||||
// OAuth providers should require email address verification to prevent this, but in
|
||||
// practice that is not always the case; this helps protect against that.
|
||||
const userByEmail = profile.email
|
||||
? await getUserByEmail(profile.email)
|
||||
: null
|
||||
if (userByEmail) {
|
||||
const provider = options.provider as OAuthConfig<any>
|
||||
if (provider?.allowDangerousEmailAccountLinking) {
|
||||
// If you trust the oauth provider to correctly verify email addresses, you can opt-in to
|
||||
// account linking even when the user is not signed-in.
|
||||
user = userByEmail
|
||||
} else {
|
||||
// We end up here when we don't have an account with the same [provider].id *BUT*
|
||||
// we do already have an account with the same email address as the one in the
|
||||
// OAuth profile the user has just tried to sign in with.
|
||||
//
|
||||
// We don't want to have two accounts with the same email address, and we don't
|
||||
// want to link them in case it's not safe to do so, so instead we prompt the user
|
||||
// to sign in via email to verify their identity and then link the accounts.
|
||||
throw new OAuthAccountNotLinked(
|
||||
"Another account already exists with the same e-mail address",
|
||||
{ provider: account.provider }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// If the current user is not logged in and the profile isn't linked to any user
|
||||
// accounts (by email or provider account id)...
|
||||
//
|
||||
// If no account matching the same [provider].id or .email exists, we can
|
||||
// create a new account for the user, link it to the OAuth account and
|
||||
// create a new session for them so they are signed in with it.
|
||||
const { id: _, ...newUser } = { ...profile, emailVerified: null }
|
||||
user = await createUser(newUser)
|
||||
}
|
||||
await events.createUser?.({ user })
|
||||
|
||||
await linkAccount({ ...account, userId: user.id })
|
||||
await events.linkAccount?.({ user, account, profile })
|
||||
|
||||
session = useJwtSession
|
||||
? {}
|
||||
: await createSession({
|
||||
sessionToken: generateSessionToken(),
|
||||
userId: user.id,
|
||||
expires: fromDate(options.session.maxAge),
|
||||
})
|
||||
|
||||
return { session, user, isNewUser: true }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,8 +159,17 @@ export class SessionStore {
|
||||
* The JWT Session or database Session ID
|
||||
* constructed from the cookie chunks.
|
||||
*/
|
||||
get value() {
|
||||
return Object.values(this.#chunks)?.join("")
|
||||
get value() {
|
||||
// Sort the chunks by their keys before joining
|
||||
const sortedKeys = Object.keys(this.#chunks).sort((a, b) => {
|
||||
const aSuffix = parseInt(a.split(".")[1] || "0");
|
||||
const bSuffix = parseInt(b.split(".")[1] || "0");
|
||||
|
||||
return aSuffix - bSuffix;
|
||||
});
|
||||
|
||||
// Use the sorted keys to join the chunks in the correct order
|
||||
return sortedKeys.map(key => this.#chunks[key]).join("");
|
||||
}
|
||||
|
||||
/** Given a cookie, return a list of cookies, chunked to fit the allowed cookie size. */
|
||||
|
||||
@@ -47,7 +47,7 @@ export async function AuthInternal<
|
||||
case "providers":
|
||||
return (await routes.providers(options.providers)) as any
|
||||
case "session": {
|
||||
const session = await routes.session(sessionStore, options)
|
||||
const session = await routes.session({ sessionStore, options })
|
||||
if (session.cookies) cookies.push(...session.cookies)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
return { ...session, cookies } as any
|
||||
@@ -110,14 +110,10 @@ export async function AuthInternal<
|
||||
if (
|
||||
[
|
||||
"Signin",
|
||||
"OAuthSignin",
|
||||
"OAuthCallback",
|
||||
"OAuthCreateAccount",
|
||||
"EmailCreateAccount",
|
||||
"Callback",
|
||||
"OAuthAccountNotLinked",
|
||||
"EmailSignin",
|
||||
"CredentialsSignin",
|
||||
"SessionRequired",
|
||||
].includes(error as string)
|
||||
) {
|
||||
@@ -181,6 +177,22 @@ export async function AuthInternal<
|
||||
return { ...callback, cookies }
|
||||
}
|
||||
break
|
||||
case "session": {
|
||||
if (options.csrfTokenVerified) {
|
||||
const session = await routes.session({
|
||||
options,
|
||||
sessionStore,
|
||||
newSession: request.body?.data,
|
||||
isUpdate: true,
|
||||
})
|
||||
if (session.cookies) cookies.push(...session.cookies)
|
||||
return { ...session, cookies } as any
|
||||
}
|
||||
|
||||
// If CSRF token is invalid, return a 400 status code
|
||||
// we should not redirect to a page as this is an API route
|
||||
return { status: 400, cookies }
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as o from "oauth4webapi"
|
||||
import { OAuthCallbackError, OAuthProfileParseError } from "../../errors.js"
|
||||
|
||||
import type {
|
||||
Account,
|
||||
InternalOptions,
|
||||
LoggerInstance,
|
||||
Profile,
|
||||
@@ -88,11 +89,9 @@ export async function handleOAuth(
|
||||
|
||||
/** https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1 */
|
||||
if (o.isOAuth2Error(codeGrantParams)) {
|
||||
logger.debug("OAuthCallbackError", {
|
||||
providerId: provider.id,
|
||||
...codeGrantParams,
|
||||
})
|
||||
throw new OAuthCallbackError(codeGrantParams.error)
|
||||
const cause = { providerId: provider.id, ...codeGrantParams }
|
||||
logger.debug("OAuthCallbackError", cause)
|
||||
throw new OAuthCallbackError("OAuth Provider returned an error", cause)
|
||||
}
|
||||
|
||||
const codeVerifier = await checks.pkce.use(cookies, resCookies, options)
|
||||
@@ -123,8 +122,8 @@ export async function handleOAuth(
|
||||
throw new Error("TODO: Handle www-authenticate challenges as needed")
|
||||
}
|
||||
|
||||
let profile: Profile = {}
|
||||
let tokens: TokenSet
|
||||
let profile: Profile
|
||||
let tokens: TokenSet & Pick<Account, "expires_at">
|
||||
|
||||
if (provider.type === "oidc") {
|
||||
const nonce = await checks.nonce.use(cookies, resCookies, options)
|
||||
@@ -162,40 +161,51 @@ export async function handleOAuth(
|
||||
(tokens as any).access_token
|
||||
)
|
||||
profile = await userinfoResponse.json()
|
||||
} else {
|
||||
throw new TypeError("No userinfo endpoint configured")
|
||||
}
|
||||
}
|
||||
|
||||
const profileResult = await getProfile(profile, provider, tokens, logger)
|
||||
if (tokens.expires_in) {
|
||||
tokens.expires_at =
|
||||
Math.floor(Date.now() / 1000) + Number(tokens.expires_in)
|
||||
}
|
||||
|
||||
return { ...profileResult, cookies: resCookies }
|
||||
const profileResult = await getUserAndAccount(
|
||||
profile,
|
||||
provider,
|
||||
tokens,
|
||||
logger
|
||||
)
|
||||
|
||||
return { ...profileResult, profile, cookies: resCookies }
|
||||
}
|
||||
|
||||
/** Returns profile, raw profile and auth provider details */
|
||||
async function getProfile(
|
||||
/** Returns the user and account that is going to be created in the database. */
|
||||
async function getUserAndAccount(
|
||||
OAuthProfile: Profile,
|
||||
provider: OAuthConfigInternal<any>,
|
||||
tokens: TokenSet,
|
||||
logger: LoggerInstance
|
||||
) {
|
||||
try {
|
||||
const profile = await provider.profile(OAuthProfile, tokens)
|
||||
profile.email = profile.email?.toLowerCase()
|
||||
const user = await provider.profile(OAuthProfile, tokens)
|
||||
user.email = user.email?.toLowerCase()
|
||||
|
||||
if (!profile.id) {
|
||||
if (!user.id) {
|
||||
throw new TypeError(
|
||||
`Profile id is missing in ${provider.name} OAuth profile response`
|
||||
`User id is missing in ${provider.name} OAuth profile response`
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
profile,
|
||||
user,
|
||||
account: {
|
||||
provider: provider.id,
|
||||
type: provider.type,
|
||||
providerAccountId: profile.id.toString(),
|
||||
providerAccountId: user.id.toString(),
|
||||
...tokens,
|
||||
},
|
||||
OAuthProfile,
|
||||
}
|
||||
} catch (e) {
|
||||
// If we didn't get a response either there was a problem with the provider
|
||||
@@ -206,6 +216,8 @@ async function getProfile(
|
||||
// redirected back to the sign up page. We log the error to help developers
|
||||
// who might be trying to debug this when configuring a new provider.
|
||||
logger.debug("getProfile error details", OAuthProfile)
|
||||
logger.error(new OAuthProfileParseError(e as Error))
|
||||
logger.error(
|
||||
new OAuthProfileParseError(e as Error, { provider: provider.id })
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ const signinErrors: Record<
|
||||
default: "Unable to sign in.",
|
||||
signin: "Try signing in with a different account.",
|
||||
oauthsignin: "Try signing in with a different account.",
|
||||
oauthcallback: "Try signing in with a different account.",
|
||||
oauthcallbackerror: "Try signing in with a different account.",
|
||||
oauthcreateaccount: "Try signing in with a different account.",
|
||||
emailcreateaccount: "Try signing in with a different account.",
|
||||
callback: "Try signing in with a different account.",
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { OAuthProfileParseError } from "../errors.js"
|
||||
import { merge } from "./utils/merge.js"
|
||||
|
||||
import type {
|
||||
AccountCallback,
|
||||
OAuthConfig,
|
||||
OAuthConfigInternal,
|
||||
OAuthEndpointType,
|
||||
OAuthUserConfig,
|
||||
ProfileCallback,
|
||||
Provider,
|
||||
} from "../providers/index.js"
|
||||
import type { AuthConfig, InternalProvider } from "../types.js"
|
||||
import type { AuthConfig, InternalProvider, Profile } from "../types.js"
|
||||
|
||||
/**
|
||||
* Adds `signinUrl` and `callbackUrl` to each provider
|
||||
@@ -77,18 +80,51 @@ function normalizeOAuth(
|
||||
checks,
|
||||
userinfo,
|
||||
profile: c.profile ?? defaultProfile,
|
||||
account: c.account ?? defaultAccount,
|
||||
}
|
||||
}
|
||||
|
||||
function defaultProfile(profile: any) {
|
||||
return {
|
||||
id: profile.sub ?? profile.id,
|
||||
name:
|
||||
profile.name ?? profile.nickname ?? profile.preferred_username ?? null,
|
||||
email: profile.email ?? null,
|
||||
image: profile.picture ?? null,
|
||||
}
|
||||
/**
|
||||
* Returns basic user profile from the userinfo response/`id_token` claims.
|
||||
* @see https://authjs.dev/reference/adapters#user
|
||||
* @see https://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
* @see https://openid.net/specs/openid-connect-core-1_0.html#UserInfo
|
||||
*/
|
||||
const defaultProfile: ProfileCallback<Profile> = (profile) => {
|
||||
const id = profile.sub ?? profile.id
|
||||
if (!id) throw new OAuthProfileParseError("Missing user id")
|
||||
return stripUndefined({
|
||||
id: id.toString(),
|
||||
name: profile.name ?? profile.nickname ?? profile.preferred_username,
|
||||
email: profile.email,
|
||||
image: profile.picture,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns basic OAuth/OIDC values from the token response.
|
||||
* @see https://www.ietf.org/rfc/rfc6749.html#section-5.1
|
||||
* @see https://openid.net/specs/openid-connect-core-1_0.html#TokenResponse
|
||||
* @see https://authjs.dev/reference/adapters#account
|
||||
*/
|
||||
const defaultAccount: AccountCallback = (account) => {
|
||||
return stripUndefined({
|
||||
access_token: account.access_token,
|
||||
id_token: account.id_token,
|
||||
refresh_token: account.refresh_token,
|
||||
expires_at: account.expires_at,
|
||||
scope: account.scope,
|
||||
token_type: account.token_type,
|
||||
session_state: account.session_state,
|
||||
})
|
||||
}
|
||||
|
||||
function stripUndefined<T extends object>(o: T): T {
|
||||
const result = {} as any
|
||||
for (let [k, v] of Object.entries(o)) v !== undefined && (result[k] = v)
|
||||
return result as T
|
||||
}
|
||||
|
||||
function normalizeEndpoint(
|
||||
e?: OAuthConfig<any>[OAuthEndpointType],
|
||||
issuer?: string
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user