diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 37c43671ca..127d2241ca 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -74,7 +74,7 @@ env: jobs: test: - name: Run release + name: Test runs-on: ubuntu-latest steps: - name: Init @@ -82,7 +82,7 @@ jobs: with: fetch-depth: 0 - name: Install pnpm - uses: pnpm/action-setup@v2.2.4 + uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v4 with: @@ -114,7 +114,7 @@ jobs: if: steps.playwright-cache.outputs.cache-hit != 'true' && github.repository == 'nextauthjs/next-auth' run: | pnpm exec playwright install --with-deps chromium - - name: Run Docker E2E + - name: Run E2E tests (Nextjs-Docker) continue-on-error: true if: false timeout-minutes: 15 @@ -148,7 +148,7 @@ jobs: name: playwright-traces path: "**/packages/utils/test-results/*/trace.zip" retention-days: 7 - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v4 if: always() name: Coverage with: @@ -156,21 +156,22 @@ jobs: release-branch: name: Publish branch + timeout-minutes: 120 runs-on: ubuntu-latest needs: test if: ${{ github.event_name == 'push' }} environment: Production steps: - name: Init - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 # Please upvote https://github.com/orgs/community/discussions/13836 token: ${{ secrets.GH_PAT }} - name: Install pnpm - uses: pnpm/action-setup@v2.2.4 + uses: pnpm/action-setup@v4 - name: Setup Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: cache: "pnpm" - name: Install dependencies @@ -183,17 +184,18 @@ jobs: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} release-pr: name: Publish PR + timeout-minutes: 120 runs-on: ubuntu-latest needs: test if: ${{ github.event_name == 'pull_request' }} environment: Preview steps: - name: Init - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install pnpm - uses: pnpm/action-setup@v2.2.4 + uses: pnpm/action-setup@v4 - name: Setup Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: "pnpm" @@ -228,11 +230,11 @@ jobs: if: ${{ github.event_name == 'workflow_dispatch' }} steps: - name: Init - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install pnpm - uses: pnpm/action-setup@v2.2.4 + uses: pnpm/action-setup@v4 - name: Setup Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: "pnpm" diff --git a/apps/dev/express/src/app.ts b/apps/dev/express/src/app.ts index 27cc8db60c..6157373064 100644 --- a/apps/dev/express/src/app.ts +++ b/apps/dev/express/src/app.ts @@ -56,7 +56,7 @@ app.get( authenticatedUser, async (_req: Request, res: Response) => { res.json(res.locals.session) - }, + } ) app.get("/", async (_req: Request, res: Response) => { diff --git a/apps/examples/nextjs/Dockerfile b/apps/examples/nextjs/Dockerfile index 525aaea3e4..2c27bcee0a 100644 --- a/apps/examples/nextjs/Dockerfile +++ b/apps/examples/nextjs/Dockerfile @@ -7,8 +7,8 @@ RUN apk add --no-cache libc6-compat WORKDIR /app # Install dependencies -COPY package.json ./ -RUN npm i +COPY package.json pnpm-lock.yaml ./ +RUN corepack enable && pnpm install # Rebuild the source code only when needed @@ -54,4 +54,4 @@ ENV PORT 3000 # server.js is created by next build from the standalone output # https://nextjs.org/docs/pages/api-reference/next-config-js/output -CMD HOSTNAME="0.0.0.0" node server.js \ No newline at end of file +CMD HOSTNAME="0.0.0.0" node server.js diff --git a/apps/examples/nextjs/app/[...proxy]/route.tsx b/apps/examples/nextjs/app/[...proxy]/route.tsx index 6e28669335..26f1449ae0 100644 --- a/apps/examples/nextjs/app/[...proxy]/route.tsx +++ b/apps/examples/nextjs/app/[...proxy]/route.tsx @@ -13,7 +13,7 @@ function stripContentEncoding(result: Response) { }) } -export async function handler(request: NextRequest) { +async function handler(request: NextRequest) { const session = await auth() const headers = new Headers(request.headers) diff --git a/apps/examples/nextjs/docker-compose.yml b/apps/examples/nextjs/docker-compose.yml new file mode 100644 index 0000000000..e5408dd83f --- /dev/null +++ b/apps/examples/nextjs/docker-compose.yml @@ -0,0 +1,17 @@ +version: "3" + +services: + authjs-docker-test: + environment: + - TEST_KEYCLOAK_USERNAME + - TEST_KEYCLOAK_PASSWORD + - AUTH_KEYCLOAK_ID + - AUTH_KEYCLOAK_SECRET + - AUTH_KEYCLOAK_ISSUER + - AUTH_SECRET="MohY0/2zSQw/psWEnejC2ka3Al0oifvY4YjOkUaFfnI=" + - AUTH_URL=http://localhost:3000/auth + build: + context: . + dockerfile: Dockerfile + ports: + - "3000:3000" diff --git a/apps/examples/nextjs/test-docker.sh b/apps/examples/nextjs/test-docker.sh new file mode 100755 index 0000000000..824fdb3e9f --- /dev/null +++ b/apps/examples/nextjs/test-docker.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +# Easier to read `docker-compose up` output +# export BUILDKIT_PROGRESS=plain + +args=("-f" "docker-compose.yml") +if [[ -z "${CI}" ]]; then + args+=("--env-file" ".env") +fi +args+=("up" "--detach" "--build") + +echo "Running: docker-compose ${args[*]}" + +if ! docker-compose "${args[@]}"; then + echo "Failed to start container" + exit 1 +fi + +echo "waiting 10 seconds for container to start..." +sleep 10 + +# Used to control which env vars to load in the playwright process +export TEST_DOCKER=1 + +# Always stop container, but exit with 1 when tests are failing +if playwright test -c ../../../packages/utils/playwright.config.ts; then + docker-compose down +else + docker-compose down && exit 1 +fi diff --git a/packages/adapter-azure-tables/src/index.ts b/packages/adapter-azure-tables/src/index.ts index 232beef223..d96c6a5769 100644 --- a/packages/adapter-azure-tables/src/index.ts +++ b/packages/adapter-azure-tables/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

An official Azure Table Storage adapter for Auth.js / NextAuth.js.

+ *

An official Azure Table Storage adapter for Auth.js / NextAuth.js.

* * * @@ -51,46 +51,7 @@ export function withoutKeys( return entity } -/** - * - * 1. Create a table for authentication data, `auth` in the example below. - * - * ```js title="auth.ts" - * import type { AuthConfig } from "next-auth" - * import { TableStorageAdapter } from "@next-auth/azure-tables-adapter" - * import { AzureNamedKeyCredential, TableClient } from "@azure/data-tables" - * - * const credential = new AzureNamedKeyCredential( - * process.env.AZURE_ACCOUNT, - * process.env.AZURE_ACCESS_KEY - * ) - * const authClient = new TableClient( - * process.env.AZURE_TABLES_ENDPOINT, - * "auth", - * credential - * ) - * - * // For more information on each option (and a full list of options) go to - * // https://authjs.dev/reference/core/types#authconfig - * export default const authConfig = { - * // https://authjs.dev/getting-started/authentication/oauth - * providers: [ - * // ... - * ], - * adapter: TableStorageAdapter(authClient), - * // ... - * } satisfies AuthConfig - * ``` - * - * Environment variable are as follows: - * - * ``` - * AZURE_ACCOUNT=storageaccountname - * AZURE_ACCESS_KEY=longRandomKey - * AZURE_TABLES_ENDPOINT=https://$AZURE_ACCOUNT.table.core.windows.net - * ``` - * - */ + export const TableStorageAdapter = (client: TableClient): Adapter => { return { async createUser(user) { diff --git a/packages/adapter-d1/src/index.ts b/packages/adapter-d1/src/index.ts index 8b75db41f9..cfa496ddf3 100644 --- a/packages/adapter-d1/src/index.ts +++ b/packages/adapter-d1/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

An official Cloudflare D1 adapter for Auth.js / NextAuth.js.

+ *

An official Cloudflare D1 adapter for Auth.js / NextAuth.js.

* * * diff --git a/packages/adapter-drizzle/src/index.ts b/packages/adapter-drizzle/src/index.ts index 024a72228a..6fa34f49bc 100644 --- a/packages/adapter-drizzle/src/index.ts +++ b/packages/adapter-drizzle/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

Official Drizzle ORM adapter for Auth.js / NextAuth.js.

+ *

Official Drizzle ORM adapter for Auth.js / NextAuth.js.

* * * @@ -26,250 +26,7 @@ import { DefaultSQLiteSchema, SQLiteDrizzleAdapter } from "./lib/sqlite.js" import { DefaultSchema, SqlFlavorOptions } from "./lib/utils.js" import type { Adapter } from "@auth/core/adapters" -/** - * Create db instance and pass it to adapter. Add this adapter to your `auth.ts` Auth.js configuration object: - * - * ```ts title="auth.ts" - * import NextAuth from "next-auth" - * import Google from "next-auth/providers/google" - * import { DrizzleAdapter } from "@auth/drizzle-adapter" - * import { db } from "./db.ts" - * - * export const { handlers, auth } = NextAuth({ - * adapter: DrizzleAdapter(db), - * providers: [ - * Google, - * ], - * }) - * ``` - * - * Follow the Drizzle documentation for [PostgreSQL setup](https://orm.drizzle.team/docs/get-started-postgresql), [MySQL setup](https://orm.drizzle.team/docs/get-started-mysql) and [SQLite setup](https://orm.drizzle.team/docs/get-started-sqlite). - * - * :::info - * If you want to use your own tables, you can pass them as a second argument. If you add non-nullable columns, make sure to provide a default value or rewrite functions to handle the missing values. - * ::: - * - * ```ts title="auth.ts" - * import NextAuth from "next-auth" - * import Google from "next-auth/providers/google" - * import { DrizzleAdapter } from "@auth/drizzle-adapter" - * import { accounts, sessions, users, verificationTokens } from "./schema" - * import { db } from "./db.ts" - * - * export const { handlers, auth } = NextAuth({ - * adapter: DrizzleAdapter(db, { usersTable: users, accountsTable: accounts, sessionsTable: sessions, verificationTokensTable: verificationTokens }), - * providers: [ - * Google, - * ], - * }) - * ``` - * - * ## Setup - * - * First, create a schema that includes [the minimum requirements for a `next-auth` adapter](/reference/core/adapters#models). You can select your favorite SQL flavor below and copy it. - * Additionally, you may extend the schema from the minimum requirements to suit your needs. - * - * - [Postgres](#postgres) - * - [MySQL](#mysql) - * - [SQLite](#sqlite) - * - * ### Postgres - * ```ts title="schema.ts" - * import { - * timestamp, - * pgTable, - * text, - * primaryKey, - * integer - * } from "drizzle-orm/pg-core" - * import type { AdapterAccountType } from '@auth/core/adapters' - * - * export const users = pgTable("user", { - * id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()), - * name: text("name"), - * email: text("email").notNull(), - * emailVerified: timestamp("emailVerified", { mode: "date" }), - * image: text("image"), - * }) - * - * export const accounts = pgTable( - * "account", - * { - * userId: text("userId") - * .notNull() - * .references(() => users.id, { onDelete: "cascade" }), - * type: text("type").$type().notNull(), - * provider: text("provider").notNull(), - * providerAccountId: text("providerAccountId").notNull(), - * refresh_token: text("refresh_token"), - * access_token: text("access_token"), - * expires_at: integer("expires_at"), - * token_type: text("token_type"), - * scope: text("scope"), - * id_token: text("id_token"), - * session_state: text("session_state"), - * }, - * (account) => ({ - * compoundKey: primaryKey({ columns: [account.provider, account.providerAccountId] }), - * }) - * ) - * - * export const sessions = pgTable("session", { - * sessionToken: text("sessionToken").primaryKey(), - * userId: text("userId") - * .notNull() - * .references(() => users.id, { onDelete: "cascade" }), - * expires: timestamp("expires", { mode: "date" }).notNull(), - * }) - * - * export const verificationTokens = pgTable( - * "verificationToken", - * { - * identifier: text("identifier").notNull(), - * token: text("token").notNull(), - * expires: timestamp("expires", { mode: "date" }).notNull(), - * }, - * (vt) => ({ - * compoundKey: primaryKey({ columns: [vt.identifier, vt.token] }), - * }) - * ) - * ``` - * - * ### MySQL - * - * In MySQL, there's no `returning` clause, so in the `createUser` function, we first insert a new user and then search by `email` to get the user's data. To make the search faster, we suggest adding an index to the `email` column. - * - * ```ts title="schema.ts" - * import { - * int, - * timestamp, - * mysqlTable, - * primaryKey, - * varchar, - * } from "drizzle-orm/mysql-core" - * import type { AdapterAccountType } from "@auth/core/adapters" - * - * export const users = mysqlTable("user", { - * id: varchar("id", { length: 255 }).primaryKey().$defaultFn(() => crypto.randomUUID()), - * name: varchar("name", { length: 255 }), - * email: varchar("email", { length: 255 }).notNull(), - * emailVerified: timestamp("emailVerified", { mode: "date", fsp: 3 }), - * image: varchar("image", { length: 255 }), - * }) - * - * export const accounts = mysqlTable( - * "account", - * { - * userId: varchar("userId", { length: 255 }) - * .notNull() - * .references(() => users.id, { onDelete: "cascade" }), - * type: varchar("type", { length: 255 }).$type().notNull(), - * provider: varchar("provider", { length: 255 }).notNull(), - * providerAccountId: varchar("providerAccountId", { length: 255 }).notNull(), - * refresh_token: varchar("refresh_token", { length: 255 }), - * access_token: varchar("access_token", { length: 255 }), - * expires_at: int("expires_at"), - * token_type: varchar("token_type", { length: 255 }), - * scope: varchar("scope", { length: 255 }), - * id_token: varchar("id_token", { length: 2048 }), - * session_state: varchar("session_state", { length: 255 }), - * }, - * (account) => ({ - * compoundKey: primaryKey({ - columns: [account.provider, account.providerAccountId], - }) - * }) - * ) - * - * export const sessions = mysqlTable("session", { - * sessionToken: varchar("sessionToken", { length: 255 }).primaryKey(), - * userId: varchar("userId", { length: 255 }) - * .notNull() - * .references(() => users.id, { onDelete: "cascade" }), - * expires: timestamp("expires", { mode: "date" }).notNull(), - * }) - * - * export const verificationTokens = mysqlTable( - * "verificationToken", - * { - * identifier: varchar("identifier", { length: 255 }).notNull(), - * token: varchar("token", { length: 255 }).notNull(), - * expires: timestamp("expires", { mode: "date" }).notNull(), - * }, - * (vt) => ({ - * compoundKey: primaryKey({ columns: [vt.identifier, vt.token] }), - * }) - * ) - * ``` - * - * ### SQLite - * - * ```ts title="schema.ts" - * import { integer, sqliteTable, text, primaryKey } from "drizzle-orm/sqlite-core" - * import type { AdapterAccountType } from "@auth/core/adapters" - * - * export const users = sqliteTable("user", { - * id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()), - * name: text("name"), - * email: text("email").notNull(), - * emailVerified: integer("emailVerified", { mode: "timestamp_ms" }), - * image: text("image"), - * }) - * - * export const accounts = sqliteTable( - * "account", - * { - * userId: text("userId") - * .notNull() - * .references(() => users.id, { onDelete: "cascade" }), - * type: text("type").$type().notNull(), - * provider: text("provider").notNull(), - * providerAccountId: text("providerAccountId").notNull(), - * refresh_token: text("refresh_token"), - * access_token: text("access_token"), - * expires_at: integer("expires_at"), - * token_type: text("token_type"), - * scope: text("scope"), - * id_token: text("id_token"), - * session_state: text("session_state"), - * }, - * (account) => ({ - * compoundKey: primaryKey({ - columns: [account.provider, account.providerAccountId], - }) - * }) - * ) - * - * export const sessions = sqliteTable("session", { - * sessionToken: text("sessionToken").primaryKey(), - * userId: text("userId") - * .notNull() - * .references(() => users.id, { onDelete: "cascade" }), - * expires: integer("expires", { mode: "timestamp_ms" }).notNull(), - * }) - * - * export const verificationTokens = sqliteTable( - * "verificationToken", - * { - * identifier: text("identifier").notNull(), - * token: text("token").notNull(), - * expires: integer("expires", { mode: "timestamp_ms" }).notNull(), - * }, - * (vt) => ({ - * compoundKey: primaryKey({ columns: [vt.identifier, vt.token] }), - * }) - * ) - * ``` - * - * ## Migrating your database - * With your schema now described in your code, you'll need to migrate your database to your schema. - * - * For full documentation on how to run migrations with Drizzle, [visit the Drizzle documentation](https://orm.drizzle.team/kit-docs/overview#running-migrations) or check how to apply changes directly to the database with [push command](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push). - * - * --- - * - **/ export function DrizzleAdapter( db: SqlFlavor, schema?: DefaultSchema diff --git a/packages/adapter-drizzle/test/mysql/schema.ts b/packages/adapter-drizzle/test/mysql/schema.ts index 70b07a4d1f..6cd768417d 100644 --- a/packages/adapter-drizzle/test/mysql/schema.ts +++ b/packages/adapter-drizzle/test/mysql/schema.ts @@ -10,7 +10,7 @@ export const { } = defineTables({}) const poolConnection = createPool({ - host: "localhost", + host: "127.0.0.1", user: "root", password: "password", database: "next-auth", diff --git a/packages/adapter-drizzle/test/mysql/test.sh b/packages/adapter-drizzle/test/mysql/test.sh index b2ea3b3628..c59896e813 100755 --- a/packages/adapter-drizzle/test/mysql/test.sh +++ b/packages/adapter-drizzle/test/mysql/test.sh @@ -11,16 +11,17 @@ docker run -d --rm \ -e MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} \ --name "${MYSQL_CONTAINER_NAME}" \ -p 3306:3306 \ - mysql:8 \ - --default-authentication-plugin=mysql_native_password + mysql:8 -echo "Waiting 10s for db to start..." && sleep 10 +echo "Waiting 15s for db to start..." && sleep 15 -# Push schema and seed +# Generate Migration from Schema drizzle-kit generate:mysql --config=./test/mysql/drizzle.config.ts -NODE_OPTIONS='--import tsx' + +# Push Schema to DB tsx ./test/mysql/migrator.ts +# Run Tests if vitest run -c ../utils/vitest.config.ts ./test/mysql/index.test.ts; then docker stop ${MYSQL_CONTAINER_NAME} else diff --git a/packages/adapter-drizzle/test/pg/schema.ts b/packages/adapter-drizzle/test/pg/schema.ts index a24fe43a35..e69ec01af2 100644 --- a/packages/adapter-drizzle/test/pg/schema.ts +++ b/packages/adapter-drizzle/test/pg/schema.ts @@ -9,7 +9,7 @@ export const { verificationTokensTable, } = defineTables({}) -const connectionString = "postgres://nextauth:nextauth@localhost:5432/nextauth" +const connectionString = "postgres://nextauth:nextauth@127.0.0.1:5432/nextauth" const sql = postgres(connectionString) export const db = drizzle(sql) diff --git a/packages/adapter-dynamodb/src/index.ts b/packages/adapter-dynamodb/src/index.ts index 2db86bc553..53d3de3127 100644 --- a/packages/adapter-dynamodb/src/index.ts +++ b/packages/adapter-dynamodb/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

Official DynamoDB adapter for Auth.js / NextAuth.js.

+ *

Official DynamoDB adapter for Auth.js / NextAuth.js.

* * * @@ -36,182 +36,6 @@ export interface DynamoDBAdapterOptions { indexSortKey?: string } -/** - * ## Setup - * - * By default, the adapter expects a table with a partition key `pk` and a sort key `sk`, as well as a global secondary index named `GSI1` with `GSI1PK` as partition key and `GSI1SK` as sorting key. To automatically delete sessions and verification requests after they expire using [dynamodb TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html) you should [enable the TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/time-to-live-ttl-how-to.html) with attribute name 'expires'. You can set whatever you want as the table name and the billing method. - * You can find the full schema in the table structure section below. - * - * ### Configuring Auth.js - * - * You need to pass `DynamoDBDocument` client from the modular [`aws-sdk`](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/dynamodb-example-dynamodb-utilities.html) v3 to the adapter. - * The default table name is `next-auth`, but you can customise that by passing `{ tableName: 'your-table-name' }` as the second parameter in the adapter. - * - * ```js title="pages/api/auth/[...nextauth].js" - * import { DynamoDB, DynamoDBClientConfig } from "@aws-sdk/client-dynamodb" - * import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb" - * import NextAuth from "next-auth"; - * import Providers from "next-auth/providers"; - * import { DynamoDBAdapter } from "@auth/dynamodb-adapter" - * - * const config: DynamoDBClientConfig = { - * credentials: { - * accessKeyId: process.env.NEXT_AUTH_AWS_ACCESS_KEY, - * secretAccessKey: process.env.NEXT_AUTH_AWS_SECRET_KEY, - * }, - * region: process.env.NEXT_AUTH_AWS_REGION, - * }; - * - * const client = DynamoDBDocument.from(new DynamoDB(config), { - * marshallOptions: { - * convertEmptyValues: true, - * removeUndefinedValues: true, - * convertClassInstanceToMap: true, - * }, - * }) - * - * export default NextAuth({ - * // Configure one or more authentication providers - * providers: [ - * Providers.GitHub({ - * clientId: process.env.GITHUB_ID, - * clientSecret: process.env.GITHUB_SECRET, - * }), - * Providers.Email({ - * server: process.env.EMAIL_SERVER, - * from: process.env.EMAIL_FROM, - * }), - * // ...add more providers here - * ], - * adapter: DynamoDBAdapter( - * client - * ), - * }); - * ``` - * - * (AWS secrets start with `NEXT_AUTH_` in order to not conflict with [Vercel's reserved environment variables](https://vercel.com/docs/environment-variables#reserved-environment-variables).) - * - * ## AWS Credentials - * - * :::note - * Always follow the **principle of least privilege** when giving access to AWS - * services/resources -> identities should only be permitted to perform the - * smallest set of actions necessary to fulfill a specific task. - * ::: - * - * 1. Open the [AWS console](https://console.aws.amazon.com/) and go to "IAM", then "Users". - * 2. Create a new user. The purpose of this user is to give programmatic access to DynamoDB. - * 3. Create an Access Key and then copy Key ID and Secret to your `.env`/`.env.local` file. - * 4. Select "Add Permission" and "Create Inline Policy". - * 5. Copy the JSON below into the JSON input and replace `region`, `account_id` and `table_name` with your values. - * - * ```json - * { - * "Version": "2012-10-17", - * "Statement": [ - * { - * "Sid": "DynamoDBAccess", - * "Effect": "Allow", - * "Action": [ - * "dynamodb:BatchGetItem", - * "dynamodb:BatchWriteItem", - * "dynamodb:Describe*", - * "dynamodb:List*", - * "dynamodb:PutItem", - * "dynamodb:DeleteItem", - * "dynamodb:GetItem", - * "dynamodb:Scan", - * "dynamodb:Query", - * "dynamodb:UpdateItem" - * ], - * "Resource": [ - * "arn:aws:dynamodb:{region}:{account_id}:table/{table_name}", - * "arn:aws:dynamodb:{region}:{account_id}:table/{table_name}/index/GSI1" - * ] - * } - * ] - * } - * ``` - * - * ## Advanced usage - * - * ### Default schema - * - * The table respects the single table design pattern. This has many advantages: - * - * - Only one table to manage, monitor and provision. - * - Querying relations is faster than with multi-table schemas (for eg. retrieving all sessions for a user). - * - Only one table needs to be replicated if you want to go multi-region. - * - * > This schema is adapted for use in DynamoDB and based upon our main [schema](https://authjs.dev/reference/core/adapters#models) - * - * ![DynamoDB Table](https://i.imgur.com/hGZtWDq.png) - * - * You can create this table with infrastructure as code using [`aws-cdk`](https://github.com/aws/aws-cdk) with the following table definition: - * - * ```js title="stack.ts" - * new dynamodb.Table(this, `NextAuthTable`, { - * tableName: "next-auth", - * partitionKey: { name: "pk", type: dynamodb.AttributeType.STRING }, - * sortKey: { name: "sk", type: dynamodb.AttributeType.STRING }, - * timeToLiveAttribute: "expires", - * }).addGlobalSecondaryIndex({ - * indexName: "GSI1", - * partitionKey: { name: "GSI1PK", type: dynamodb.AttributeType.STRING }, - * sortKey: { name: "GSI1SK", type: dynamodb.AttributeType.STRING }, - * }) - * ``` - * - * Alternatively, you can use this cloudformation template: - * - * ```yaml title=cloudformation.yaml - * NextAuthTable: - * Type: "AWS::DynamoDB::Table" - * Properties: - * TableName: next-auth - * AttributeDefinitions: - * - AttributeName: pk - * AttributeType: S - * - AttributeName: sk - * AttributeType: S - * - AttributeName: GSI1PK - * AttributeType: S - * - AttributeName: GSI1SK - * AttributeType: S - * KeySchema: - * - AttributeName: pk - * KeyType: HASH - * - AttributeName: sk - * KeyType: RANGE - * GlobalSecondaryIndexes: - * - IndexName: GSI1 - * Projection: - * ProjectionType: ALL - * KeySchema: - * - AttributeName: GSI1PK - * KeyType: HASH - * - AttributeName: GSI1SK - * KeyType: RANGE - * TimeToLiveSpecification: - * AttributeName: expires - * Enabled: true - * ``` - * - * ### Using a custom schema - * - * You can configure your custom table schema by passing the `options` key to the adapter constructor: - * - * ```js - * const adapter = DynamoDBAdapter(client, { - * tableName: "custom-table-name", - * partitionKey: "custom-pk", - * sortKey: "custom-sk", - * indexName: "custom-index-name", - * indexPartitionKey: "custom-index-pk", - * indexSortKey: "custom-index-sk", - * }) - * ``` - **/ export function DynamoDBAdapter( client: DynamoDBDocument, options?: DynamoDBAdapterOptions diff --git a/packages/adapter-edgedb/src/index.ts b/packages/adapter-edgedb/src/index.ts index 7f61593499..4e13a41f56 100644 --- a/packages/adapter-edgedb/src/index.ts +++ b/packages/adapter-edgedb/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

Official Edge DB adapter for Auth.js / NextAuth.js.

+ *

Official Edge DB adapter for Auth.js / NextAuth.js.

* * * @@ -24,222 +24,6 @@ import type { } from "@auth/core/adapters" import type { Client } from "edgedb" -/** - * - * To use this Adapter, you need to install `edgedb`, `@edgedb/generate`, and the separate `@auth/edgedb-adapter` package: - * - * ```bash npm2yarn - * npm install edgedb @auth/edgedb-adapter - * npm install @edgedb/generate --save-dev - * ``` - * - * ## Installation - * - * First, ensure you have the EdgeDB CLI installed. - * - * Follow the instructions below, or read the [EdgeDB quickstart](https://www.edgedb.com/docs/intro/quickstart) to install the EdgeDB CLI and initialize a project - * - * ### Linux or macOS - * - * ```bash - * curl --proto '=https' --tlsv1.2 -sSf https://sh.edgedb.com | sh - * ``` - * - * ### Windows - * - * ```powershell - * iwr https://ps1.edgedb.com -useb | iex - * ``` - * - * Check that the CLI is available with the `edgedb --version` command. If you get a `Command not found` error, you may need to open a new terminal window before the `edgedb` command is available. - * - * Once the CLI is installed, initialize a project from the application’s root directory. You’ll be presented with a series of prompts. - * - * ```bash - * edgedb project init - * ``` - * - * This process will spin up an EdgeDB instance and [“link”](https://www.edgedb.com/docs/cli/edgedb_instance/edgedb_instance_link#edgedb-instance-link) it with your current directory. As long as you’re inside that directory, CLI commands and client libraries will be able to connect to the linked instance automatically, without additional configuration. - * - * ## Setup - * - * ### NextAuth.js configuration - * - * Configure your NextAuth.js to use the EdgeDB Adapter: - * - * ```js title="pages/api/auth/[...nextauth].js" - * import NextAuth from "next-auth" - * import GoogleProvider from "next-auth/providers/google" - * import { EdgeDBAdapter } from "@auth/edgedb-adapter" - * import { createClient } from "edgedb" - * - * const client = createClient() - * - * export default NextAuth({ - * adapter: EdgeDBAdapter(client), - * providers: [ - * GoogleProvider({ - * clientId: process.env.GOOGLE_CLIENT_ID, - * clientSecret: process.env.GOOGLE_CLIENT_SECRET, - * }), - * ], - * }) - * ``` - * - * ### Create the EdgeDB schema - * - * Replace the contents of the auto-generated file in `dbschema/default.esdl` with the following: - * - * > This schema is adapted for use in EdgeDB and based upon our main [schema](https://authjs.dev/getting-started/adapters#models) - * - * ```json title="default.esdl" - * module default { - * type User { - * property name -> str; - * required property email -> str { - * constraint exclusive; - * }; - * property emailVerified -> datetime; - * property image -> str; - * multi link accounts := . datetime { - * default := datetime_current(); - * }; - * } - * - * type Account { - * required property userId := .user.id; - * required property type -> str; - * required property provider -> str; - * required property providerAccountId -> str { - * constraint exclusive; - * }; - * property refresh_token -> str; - * property access_token -> str; - * property expires_at -> int64; - * property token_type -> str; - * property scope -> str; - * property id_token -> str; - * property session_state -> str; - * required link user -> User { - * on target delete delete source; - * }; - * property createdAt -> datetime { - * default := datetime_current(); - * }; - * constraint exclusive on ((.provider, .providerAccountId)); - * } - * - * type Session { - * required property sessionToken -> str { - * constraint exclusive; - * }; - * required property userId := .user.id; - * required property expires -> datetime; - * required link user -> User { - * on target delete delete source; - * }; - * property createdAt -> datetime { - * default := datetime_current(); - * }; - * } - * - * type VerificationToken { - * required property identifier -> str; - * required property token -> str { - * constraint exclusive; - * }; - * required property expires -> datetime; - * property createdAt -> datetime { - * default := datetime_current(); - * }; - * - * constraint exclusive on ((.identifier, .token)); - * } - * } - * - * # Disable the application of access policies within access policies - * # themselves. This behavior will become the default in EdgeDB 3.0. - * # See: https://www.edgedb.com/docs/reference/ddl/access_policies#nonrecursive - * - * using future nonrecursive_access_policies; - * ``` - * - * ### Migrate the database schema - * - * 1. Create a migration - * - * ```bash - * edgedb migration create - * ``` - * - * 2. Apply the migration - * - * ```bash - * edgedb migrate - * ``` - * - * To learn more about [EdgeDB migrations](https://www.edgedb.com/docs/intro/migrations#generate-a-migration) check out the [Migrations docs](https://www.edgedb.com/docs/intro/migrations). - * - * ### Generate the query builder - * - * ```bash - * npx @edgedb/generate edgeql-js - * ``` - * - * This will generate the [query builder](https://www.edgedb.com/docs/clients/js/querybuilder) so that you can write fully typed EdgeQL queries with TypeScript in a code-first way. - * - * ```ts - * const query = e.select(e.User, () => ({ - * id: true, - * email: true, - * emailVerified: true, - * name: true, - * image: true, - * filter_single: { email: "johndoe@example.com" }, - * })); - * - * return await query.run(client); - * ``` - * - * ## Deploying - * - * ### Deploy EdgeDB - * - * First deploy an EdgeDB instance on your preferred cloud provider: - * - * - [AWS](https://www.edgedb.com/docs/guides/deployment/aws_aurora_ecs) - * - [Google Cloud](https://www.edgedb.com/docs/guides/deployment/gcp) - * - [Azure](https://www.edgedb.com/docs/guides/deployment/azure_flexibleserver) - * - [DigitalOcean](https://www.edgedb.com/docs/guides/deployment/digitalocean) - * - [Fly.io](https://www.edgedb.com/docs/guides/deployment/fly_io) - * - [Docker](https://www.edgedb.com/docs/guides/deployment/docker) (cloud-agnostic) - * - * ### Find your instance’s DSN - * - * The DSN is also known as a connection string. It will have the format `edgedb://username:password@hostname:port`. The exact instructions for this depend on which cloud provider your'e deploying to. - * - * ### Set an environment variable - * - * ``` - * EDGEDB_DSN="edgedb://johndoe:supersecure@myhost.com:420" - * ``` - * - * ### Apply migrations - * - * Use the DSN to apply migrations against your remote instance. - * - * ```bash - * edgedb migrate --dsn - * ``` - * - * ### Set up a `prebuild` script - * - * Add the following `prebuild` script to your `package.json`. When your hosting provider initializes the build, it will trigger this script which will generate the query builder. The `npx @edgedb/generate edgeql-js` command will read the value of the `EDGEDB_DSN` environment variable, connect to the database, and generate the query builder before your hosting provider starts building the project. - * - * - */ export function EdgeDBAdapter(client: Client): Adapter { return { async createUser({ email, emailVerified, name, image }) { diff --git a/packages/adapter-fauna/src/index.ts b/packages/adapter-fauna/src/index.ts index a2a731fd0b..12142ab9a1 100644 --- a/packages/adapter-fauna/src/index.ts +++ b/packages/adapter-fauna/src/index.ts @@ -1,8 +1,8 @@ /** *
- *

Official Fauna adapter for Auth.js / NextAuth.js.

+ *

Official Fauna adapter for Auth.js / NextAuth.js.

* - * + * * *
* @@ -63,179 +63,6 @@ const defaultCollectionNames = { verificationToken: "VerificationToken", } -/** - * - * ## Setup - * - * This is the Fauna Adapter for [Auth.js](https://authjs.dev). This package can only be used in conjunction with the primary `next-auth` and other framework packages. It is not a standalone package. - * - * You can find the Fauna schema and seed information in the docs at [authjs.dev/reference/adapter/fauna](https://authjs.dev/reference/adapter/fauna). - * - * ### Configure Auth.js - * - * ```js title="pages/api/auth/[...nextauth].js" - * import NextAuth from "next-auth" - * import { Client } from "fauna" - * import { FaunaAdapter } from "@auth/fauna-adapter" - * - * const client = new Client({ - * secret: "secret", - * endpoint: new URL('http://localhost:8443') - * }) - * - * // For more information on each option (and a full list of options) go to - * // https://authjs.dev/reference/core/types#authconfig - * export default NextAuth({ - * // https://authjs.dev/getting-started/authentication/oauth - * providers: [], - * adapter: FaunaAdapter(client) - * }) - * ``` - * - * ### Schema - * - * Run the following FQL code inside the `Shell` tab in the Fauna dashboard to set up the appropriate collections and indexes. - * - * ```javascript - * Collection.create({ - * name: "Account", - * indexes: { - * byUserId: { - * terms: [ - * { field: "userId" } - * ] - * }, - * byProviderAndProviderAccountId: { - * terms [ - * { field: "provider" }, - * { field: "providerAccountId" } - * ] - * }, - * } - * }) - * Collection.create({ - * name: "Session", - * constraints: [ - * { - * unique: ["sessionToken"], - * status: "active", - * } - * ], - * indexes: { - * bySessionToken: { - * terms: [ - * { field: "sessionToken" } - * ] - * }, - * byUserId: { - * terms [ - * { field: "userId" } - * ] - * }, - * } - * }) - * Collection.create({ - * name: "User", - * constraints: [ - * { - * unique: ["email"], - * status: "active", - * } - * ], - * indexes: { - * byEmail: { - * terms [ - * { field: "email" } - * ] - * }, - * } - * }) - * Collection.create({ - * name: "VerificationToken", - * indexes: { - * byIdentifierAndToken: { - * terms [ - * { field: "identifier" }, - * { field: "token" } - * ] - * }, - * } - * }) - * ``` - * - * > This schema is adapted for use in Fauna and based upon our main [schema](https://authjs.dev/reference/core/adapters#models) - * - * #### Custom collection names - * If you want to use custom collection names, you can pass them as an option to the adapter, like this: - * - * ```javascript - * FaunaAdapter(client, { - * collectionNames: { - * user: "CustomUser", - * account: "CustomAccount", - * session: "CustomSession", - * verificationToken: "CustomVerificationToken", - * } - * }) - * ``` - * - * Make sure the collection names you pass to the provider match the collection names of your Fauna database. - * - * ### Migrating from v1 - * In v2, we've renamed the collections to use uppercase naming, in accordance with Fauna best practices. If you're migrating from v1, you'll need to rename your collections to match the new naming scheme. - * Additionally, we've renamed the indexes to match the new method-like index names. - * - * #### Migration script - * Run this FQL script inside a Fauna shell for the database you're migrating from v1 to v2 (it will rename your collections and indexes to match): - * - * ```javascript - * Collection.byName("accounts")!.update({ - * name: "Account" - * indexes: { - * byUserId: { - * terms: [{ field: "userId" }] - * }, - * byProviderAndProviderAccountId: { - * terms: [{ field: "provider" }, { field: "providerAccountId" }] - * }, - * account_by_provider_and_provider_account_id: null, - * accounts_by_user_id: null - * } - * }) - * Collection.byName("sessions")!.update({ - * name: "Session", - * indexes: { - * bySessionToken: { - * terms: [{ field: "sessionToken" }] - * }, - * byUserId: { - * terms: [{ field: "userId" }] - * }, - * session_by_session_token: null, - * sessions_by_user_id: null - * } - * }) - * Collection.byName("users")!.update({ - * name: "User", - * indexes: { - * byEmail: { - * terms: [{ field: "email" }] - * }, - * user_by_email: null - * } - * }) - * Collection.byName("verification_tokens")!.update({ - * name: "VerificationToken", - * indexes: { - * byIdentifierAndToken: { - * terms: [{ field: "identifier" }, { field: "token" }] - * }, - * verification_token_by_identifier_and_token: null - * } - * }) - * ``` - * - **/ export function FaunaAdapter(client: Client, config?: AdapterConfig): Adapter { const { collectionNames = defaultCollectionNames } = config || {} diff --git a/packages/adapter-firebase/src/index.ts b/packages/adapter-firebase/src/index.ts index 41ac8a21f0..5aa4196e3d 100644 --- a/packages/adapter-firebase/src/index.ts +++ b/packages/adapter-firebase/src/index.ts @@ -57,77 +57,6 @@ export interface FirebaseAdapterConfig extends AppOptions { namingStrategy?: "snake_case" | "default" } -/** - * ## Setup - * - * First, create a Firebase project and generate a service account key. Visit: `https://console.firebase.google.com/u/0/project/{project-id}/settings/serviceaccounts/adminsdk` (replace `{project-id}` with your project's id) - * - * Now you have a few options to authenticate with the Firebase Admin SDK in your app: - * - * ### Environment variables - * - Download the service account key and save it in your project. (Make sure to add the file to your `.gitignore`!) - * - Add [`GOOGLE_APPLICATION_CREDENTIALS`](https://cloud.google.com/docs/authentication/application-default-credentials#GAC) to your environment variables and point it to the service account key file. - * - The adapter will automatically pick up the environment variable and use it to authenticate with the Firebase Admin SDK. - * - * @example - * ```ts title="pages/api/auth/[...nextauth].ts" - * import NextAuth from "next-auth" - * import { FirestoreAdapter } from "@auth/firebase-adapter" - * - * export default NextAuth({ - * adapter: FirestoreAdapter(), - * // ... - * }) - * ``` - * - * ### Service account values - * - * - Download the service account key to a temporary location. (Make sure to not commit this file to your repository!) - * - Add the following environment variables to your project: `FIREBASE_PROJECT_ID`, `FIREBASE_CLIENT_EMAIL`, `FIREBASE_PRIVATE_KEY`. - * - Pass the config to the adapter, using the environment variables as shown in the example below. - * - * @example - * ```ts title="pages/api/auth/[...nextauth].ts" - * import NextAuth from "next-auth" - * import { FirestoreAdapter } from "@auth/firebase-adapter" - * import { cert } from "firebase-admin/app" - * - * export default NextAuth({ - * adapter: FirestoreAdapter({ - * credential: cert({ - * projectId: process.env.FIREBASE_PROJECT_ID, - * clientEmail: process.env.FIREBASE_CLIENT_EMAIL, - * privateKey: process.env.FIREBASE_PRIVATE_KEY, - * }) - * }) - * // ... - * }) - * ``` - * - * ### Using an existing Firestore instance - * - * If you already have a Firestore instance, you can pass that to the adapter directly instead. - * - * :::note - * When passing an instance and in a serverless environment, remember to handle duplicate app initialization. - * ::: - * - * :::tip - * You can use the {@link initFirestore} utility to initialize the app and get an instance safely. - * ::: - * - * @example - * ```ts title="pages/api/auth/[...nextauth].ts" - * import NextAuth from "next-auth" - * import { FirestoreAdapter } from "@auth/firebase-adapter" - * import { firestore } from "lib/firestore" - * - * export default NextAuth({ - * adapter: FirestoreAdapter(firestore), - * // ... - * }) - * ``` - */ export function FirestoreAdapter( config?: FirebaseAdapterConfig | Firestore ): Adapter { diff --git a/packages/adapter-hasura/src/index.ts b/packages/adapter-hasura/src/index.ts index 8686369ed5..7f4ea29528 100644 --- a/packages/adapter-hasura/src/index.ts +++ b/packages/adapter-hasura/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

Official Hasura adapter for Auth.js / NextAuth.js.

+ *

Official Hasura adapter for Auth.js / NextAuth.js.

* * * @@ -42,101 +42,6 @@ import { VerificationTokenFragmentDoc, } from "./lib/generated/graphql.js" -/** - * - * ## Setup - * - * 1. Create the Auth.js schema in your database using SQL. - * - * ```sql - * CREATE TABLE accounts ( - * id uuid DEFAULT gen_random_uuid() NOT NULL, - * type text NOT NULL, - * provider text NOT NULL, - * "providerAccountId" text NOT NULL, - * refresh_token text, - * access_token text, - * expires_at integer, - * token_type text, - * scope text, - * id_token text, - * session_state text, - * "userId" uuid NOT NULL - * ); - * - * CREATE TABLE sessions ( - * id uuid DEFAULT gen_random_uuid() NOT NULL, - * "sessionToken" text NOT NULL, - * "userId" uuid NOT NULL, - * expires timestamptz NOT NULL - * ); - * - * CREATE TABLE users ( - * id uuid DEFAULT gen_random_uuid() NOT NULL, - * name text, - * email text NOT NULL, - * "emailVerified" timestamptz, - * image text - * ); - * - * CREATE TABLE verification_tokens ( - * token text NOT NULL, - * identifier text NOT NULL, - * expires timestamptz NOT NULL - * ); - * - * CREATE TABLE provider_type ( - * value text NOT NULL - * ); - * - * ALTER TABLE ONLY accounts - * ADD CONSTRAINT accounts_pkey PRIMARY KEY (id); - * - * ALTER TABLE ONLY sessions - * ADD CONSTRAINT sessions_pkey PRIMARY KEY ("sessionToken"); - * - * ALTER TABLE ONLY users - * ADD CONSTRAINT users_email_key UNIQUE (email); - * - * ALTER TABLE ONLY users - * ADD CONSTRAINT users_pkey PRIMARY KEY (id); - * - * ALTER TABLE ONLY verification_tokens - * ADD CONSTRAINT verification_tokens_pkey PRIMARY KEY (token); - * - * ALTER TABLE ONLY provider_type - * ADD CONSTRAINT provider_type_pkey PRIMARY KEY (value); - * - * ALTER TABLE ONLY accounts - * ADD CONSTRAINT "accounts_userId_fkey" FOREIGN KEY ("userId") REFERENCES public.users(id) ON UPDATE RESTRICT ON DELETE CASCADE; - * - * ALTER TABLE ONLY sessions - * ADD CONSTRAINT "sessions_userId_fkey" FOREIGN KEY ("userId") REFERENCES public.users(id) ON UPDATE RESTRICT ON DELETE CASCADE; - * - * INSERT INTO provider_type (value) VALUES ('credentials'), ('email'), ('oauth'), ('oidc'); - * - * ALTER TABLE ONLY accounts - * ADD CONSTRAINT "accounts_type_fkey" FOREIGN KEY ("type") REFERENCES public.provider_type(value) ON UPDATE RESTRICT ON DELETE RESTRICT; - * ``` - * - * :::info - * Tips: [Track all the tables and relationships in Hasura](https://hasura.io/docs/latest/schema/postgres/using-existing-database/#step-1-track-tablesviews) - * ::: - * - * 2. Add the adapter to your `pages/api/[...nextauth].ts` next-auth configuration object. - * - * ```js title="pages/api/auth/[...nextauth].js" - * import NextAuth from "next-auth" - * import { HasuraAdapter } from "@auth/hasura-adapter" - * - * export default NextAuth({ - * adapter: HasuraAdapter({ - * endpoint: "", - * adminSecret: "", - * }), - * }) - * ``` - */ export function HasuraAdapter(client: HasuraAdapterClient): Adapter { const c = hasuraClient(client) diff --git a/packages/adapter-kysely/src/index.ts b/packages/adapter-kysely/src/index.ts index 8a12720fef..014a5f7021 100644 --- a/packages/adapter-kysely/src/index.ts +++ b/packages/adapter-kysely/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

Official Kysely adapter for Auth.js / NextAuth.js.

+ *

Official Kysely adapter for Auth.js / NextAuth.js.

* * * @@ -57,187 +57,6 @@ export const format = { }, } -/** - * - * ## Setup - * - * This adapter supports the same first party dialects that Kysely (as of v0.24.2) supports: PostgreSQL, MySQL, and SQLite. The examples below use PostgreSQL with the [pg](https://www.npmjs.com/package/pg) client. - * - * ```bash npm2yarn - * npm install pg - * npm install --save-dev @types/pg - * ``` - * - * ```ts title="pages/api/auth/[...nextauth].ts" - * import NextAuth from "next-auth" - * import GoogleProvider from "next-auth/providers/google" - * import { KyselyAdapter } from "@auth/kysely-adapter" - * import { db } from "../../../db" - * - * export default NextAuth({ - * adapter: KyselyAdapter(db), - * providers: [ - * GoogleProvider({ - * clientId: process.env.GOOGLE_CLIENT_ID, - * clientSecret: process.env.GOOGLE_CLIENT_SECRET, - * }), - * ], - * }) - * ``` - * - * Kysely's constructor requires a database interface that contains an entry with an interface for each of your tables. You can define these types manually, or use `kysely-codegen` / `prisma-kysely` to automatically generate them. Check out the default [models](/reference/core/adapters#models) required by Auth.js. - * - * ```ts title="db.ts" - * import { PostgresDialect } from "kysely" - * import { Pool } from "pg" - * - * // This adapter exports a wrapper of the original `Kysely` class called `KyselyAuth`, - * // that can be used to provide additional type-safety. - * // While using it isn't required, it is recommended as it will verify - * // that the database interface has all the fields that Auth.js expects. - * import { KyselyAuth } from "@auth/kysely-adapter" - * - * import type { GeneratedAlways } from "kysely" - * - * interface Database { - * User: { - * id: GeneratedAlways - * name: string | null - * email: string - * emailVerified: Date | null - * image: string | null - * } - * Account: { - * id: GeneratedAlways - * userId: string - * type: string - * provider: string - * providerAccountId: string - * refresh_token: string | null - * access_token: string | null - * expires_at: number | null - * token_type: string | null - * scope: string | null - * id_token: string | null - * session_state: string | null - * } - * Session: { - * id: GeneratedAlways - * userId: string - * sessionToken: string - * expires: Date - * } - * VerificationToken: { - * identifier: string - * token: string - * expires: Date - * } - * } - * - * export const db = new KyselyAuth({ - * dialect: new PostgresDialect({ - * pool: new Pool({ - * host: process.env.DATABASE_HOST, - * database: process.env.DATABASE_NAME, - * user: process.env.DATABASE_USER, - * password: process.env.DATABASE_PASSWORD, - * }), - * }), - * }) - * ``` - * - * :::note - * An alternative to manually defining types is generating them from the database schema using [kysely-codegen](https://github.com/RobinBlomberg/kysely-codegen), or from Prisma schemas using [prisma-kysely](https://github.com/valtyr/prisma-kysely). When using generated types with `KyselyAuth`, import `Codegen` and pass it as the second generic arg: - * - * ```ts - * import type { Codegen } from "@auth/kysely-adapter" - * new KyselyAuth): Promise { - * await db.schema - * .createTable("User") - * .addColumn("id", "uuid", (col) => - * col.primaryKey().defaultTo(sql`gen_random_uuid()`) - * ) - * .addColumn("name", "text") - * .addColumn("email", "text", (col) => col.unique().notNull()) - * .addColumn("emailVerified", "timestamptz") - * .addColumn("image", "text") - * .execute() - * - * await db.schema - * .createTable("Account") - * .addColumn("id", "uuid", (col) => - * col.primaryKey().defaultTo(sql`gen_random_uuid()`) - * ) - * .addColumn("userId", "uuid", (col) => - * col.references("User.id").onDelete("cascade").notNull() - * ) - * .addColumn("type", "text", (col) => col.notNull()) - * .addColumn("provider", "text", (col) => col.notNull()) - * .addColumn("providerAccountId", "text", (col) => col.notNull()) - * .addColumn("refresh_token", "text") - * .addColumn("access_token", "text") - * .addColumn("expires_at", "bigint") - * .addColumn("token_type", "text") - * .addColumn("scope", "text") - * .addColumn("id_token", "text") - * .addColumn("session_state", "text") - * .execute() - * - * await db.schema - * .createTable("Session") - * .addColumn("id", "uuid", (col) => - * col.primaryKey().defaultTo(sql`gen_random_uuid()`) - * ) - * .addColumn("userId", "uuid", (col) => - * col.references("User.id").onDelete("cascade").notNull() - * ) - * .addColumn("sessionToken", "text", (col) => col.notNull().unique()) - * .addColumn("expires", "timestamptz", (col) => col.notNull()) - * .execute() - * - * await db.schema - * .createTable("VerificationToken") - * .addColumn("identifier", "text", (col) => col.notNull()) - * .addColumn("token", "text", (col) => col.notNull().unique()) - * .addColumn("expires", "timestamptz", (col) => col.notNull()) - * .execute() - * - * await db.schema - * .createIndex("Account_userId_index") - * .on("Account") - * .column("userId") - * .execute() - * - * await db.schema - * .createIndex("Session_userId_index") - * .on("Session") - * .column("userId") - * .execute() - * } - * - * export async function down(db: Kysely): Promise { - * await db.schema.dropTable("Account").ifExists().execute() - * await db.schema.dropTable("Session").ifExists().execute() - * await db.schema.dropTable("User").ifExists().execute() - * await db.schema.dropTable("VerificationToken").ifExists().execute() - * } - * ``` - * - * > This schema is adapted for use in Kysely and is based upon our main [schema](/reference/core/adapters#models). - * - * For more information about creating and running migrations with Kysely, refer to the [Kysely migrations documentation](https://kysely.dev/docs/migrations). - * - * ### Naming conventions - * If mixed snake_case and camelCase column names is an issue for you and/or your underlying database system, we recommend using Kysely's `CamelCasePlugin` ([see the documentation here](https://kysely-org.github.io/kysely-apidoc/classes/CamelCasePlugin.html)) feature to change the field names. This won't affect NextAuth.js, but will allow you to have consistent casing when using Kysely. - */ export function KyselyAdapter(db: Kysely): Adapter { const { adapter } = db.getExecutor() const { supportsReturning } = adapter diff --git a/packages/adapter-mikro-orm/src/index.ts b/packages/adapter-mikro-orm/src/index.ts index 246d03defa..1cfa87bb62 100644 --- a/packages/adapter-mikro-orm/src/index.ts +++ b/packages/adapter-mikro-orm/src/index.ts @@ -1,8 +1,8 @@ /** *
- *

Official MikroORM adapter for Auth.js / NextAuth.js.

+ *

Official MikroORM adapter for Auth.js / NextAuth.js.

* - * + * * *
* @@ -28,111 +28,6 @@ import * as defaultEntities from "./lib/entities.js" export { defaultEntities } -/** - * ## Setup - * - * Configure Auth.js to use the MikroORM Adapter: - * - * ```ts title="pages/api/auth/[...nextauth].ts" - * import NextAuth from "next-auth" - * import { MikroOrmAdapter } from "@auth/mikro-orm-adapter" - * - * export default NextAuth({ - * adapter: MikroOrmAdapter({ - * // MikroORM options object. Ref: https://mikro-orm.io/docs/next/configuration#driver - * dbName: "./db.sqlite", - * type: "sqlite", - * debug: process.env.DEBUG === "true" || process.env.DEBUG?.includes("db"), - * }), - * providers: [], - * }) - * ``` - * - * ## Advanced usage - * - * ### Passing custom entities - * - * The MikroORM adapter ships with its own set of entities. If you'd like to extend them, you can optionally pass them to the adapter. - * - * > This schema is adapted for use in MikroORM and based upon our main [schema](https://authjs.dev/reference/core/adapters#models) - * - * ```ts title="pages/api/auth/[...nextauth].ts" - * import config from "config/mikro-orm.ts" - * import { - * Cascade, - * Collection, - * Entity, - * OneToMany, - * PrimaryKey, - * Property, - * Unique, - * } from "@mikro-orm/core" - * import { defaultEntities } from "@auth/mikro-orm-adapter" - * - * const { Account, Session } = defaultEntities - * - * @Entity() - * export class User implements defaultEntities.User { - * @PrimaryKey() - * id: string = randomUUID() - * - * @Property({ nullable: true }) - * name?: string - * - * @Property({ nullable: true }) - * @Unique() - * email?: string - * - * @Property({ type: "Date", nullable: true }) - * emailVerified: Date | null = null - * - * @Property({ nullable: true }) - * image?: string - * - * @OneToMany({ - * entity: () => Session, - * mappedBy: (session) => session.user, - * hidden: true, - * orphanRemoval: true, - * cascade: [Cascade.ALL], - * }) - * sessions = new Collection(this) - * - * @OneToMany({ - * entity: () => Account, - * mappedBy: (account) => account.user, - * hidden: true, - * orphanRemoval: true, - * cascade: [Cascade.ALL], - * }) - * accounts = new Collection(this) - * - * @Enum({ hidden: true }) - * role = "ADMIN" - * } - * - * export default NextAuth({ - * adapter: MikroOrmAdapter(config, { entities: { User } }), - * }) - * ``` - * - * ### Including default entities - * - * You may want to include the defaultEntities in your MikroORM configuration to include them in Migrations etc. - * - * To achieve that include them in your "entities" array: - * - * ```ts title="config/mikro-orm.ts" - * import { Options } from "@mikro-orm/core"; - * import { defaultEntities } from "@auth/mikro-orm-adapter" - * - * const config: Options = { - * entities: [VeryImportantEntity, ...Object.values(defaultEntities)], - * }; - * - * export default config; - * ``` - */ export function MikroOrmAdapter< D extends IDatabaseDriver = IDatabaseDriver, >( diff --git a/packages/adapter-mongodb/src/index.ts b/packages/adapter-mongodb/src/index.ts index a63434a55e..9ded9c92c8 100644 --- a/packages/adapter-mongodb/src/index.ts +++ b/packages/adapter-mongodb/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

Official MongoDB adapter for Auth.js / NextAuth.js.

+ *

Official MongoDB adapter for Auth.js / NextAuth.js.

* * * @@ -88,60 +88,6 @@ export function _id(hex?: string) { return new ObjectId(hex) } -/** - * ## Setup - * - * The MongoDB adapter does not handle connections automatically, so you will have to make sure that you pass the Adapter a `MongoClient` that is connected already. Below you can see an example how to do this. - * - * ### Add the MongoDB client - * - * ```ts - * // This approach is taken from https://github.com/vercel/next.js/tree/canary/examples/with-mongodb - * import { MongoClient } from "mongodb" - * - * if (!process.env.MONGODB_URI) { - * throw new Error('Invalid/Missing environment variable: "MONGODB_URI"') - * } - * - * const uri = process.env.MONGODB_URI - * const options = {} - * - * let client - * let clientPromise: Promise - * - * if (process.env.NODE_ENV === "development") { - * // In development mode, use a global variable so that the value - * // is preserved across module reloads caused by HMR (Hot Module Replacement). - * if (!global._mongoClientPromise) { - * client = new MongoClient(uri, options) - * global._mongoClientPromise = client.connect() - * } - * clientPromise = global._mongoClientPromise - * } else { - * // In production mode, it's best to not use a global variable. - * client = new MongoClient(uri, options) - * clientPromise = client.connect() - * } - * - * // Export a module-scoped MongoClient promise. By doing this in a - * // separate module, the client can be shared across functions. - * export default clientPromise - * ``` - * - * ### Configure Auth.js - * - * ```js - * import NextAuth from "next-auth" - * 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 - * // https://authjs.dev/reference/providers/oauth - * export default NextAuth({ - * adapter: MongoDBAdapter(clientPromise), - * }) - * ``` - **/ export function MongoDBAdapter( client: Promise, options: MongoDBAdapterOptions = {} diff --git a/packages/adapter-neo4j/src/index.ts b/packages/adapter-neo4j/src/index.ts index 6d787a3b88..d421adf974 100644 --- a/packages/adapter-neo4j/src/index.ts +++ b/packages/adapter-neo4j/src/index.ts @@ -1,8 +1,8 @@ /** *
- *

Official Neo4j adapter for Auth.js / NextAuth.js.

+ *

Official Neo4j adapter for Auth.js / NextAuth.js.

* - * + * * *
* @@ -22,113 +22,6 @@ import type { Adapter } from "@auth/core/adapters" **/ export interface Neo4jOptions extends Session {} -/** - * ## Setup - * - * Add this adapter to your `pages/api/[...nextauth].js` Auth.js configuration object. - * - * ```js title="pages/api/auth/[...nextauth].js" - * import neo4j from "neo4j-driver" - * import { Neo4jAdapter } from "@auth/neo4j-adapter" - * - * const driver = neo4j.driver( - * "bolt://localhost", - * neo4j.auth.basic("neo4j", "password") - * ) - * - * const neo4jSession = driver.session() - * - * // For more information on each option (and a full list of options) go to - * // https://authjs.dev/reference/core/types#authconfig - * export default NextAuth({ - * // https://authjs.dev/getting-started/authentication/oauth - * providers: [], - * adapter: Neo4jAdapter(neo4jSession), - * }) - * ``` - * - * ## Advanced usage - * - * ### Schema - * - * #### Node labels - * - * The following node labels are used. - * - * - User - * - Account - * - Session - * - VerificationToken - * - * #### Relationships - * - * The following relationships and relationship labels are used. - * - * - `(:User)-[:HAS_ACCOUNT]->(:Account)` - * - `(:User)-[:HAS_SESSION]->(:Session)` - * - * #### Properties - * - * This schema is adapted for use in Neo4j and is based upon our main [models](https://authjs.dev/reference/core/adapters#models). Please check there for the node properties. Relationships have no properties. - * - * #### Indexes - * - * Optimum indexes will vary on your edition of Neo4j i.e. community or enterprise, and in case you have your own additional data on the nodes. Below are basic suggested indexes. - * - * 1. For **both** Community Edition & Enterprise Edition create constraints and indexes - * - * ```sql - * CREATE CONSTRAINT user_id_constraint IF NOT EXISTS - * ON (u:User) ASSERT u.id IS UNIQUE; - * - * CREATE INDEX user_id_index IF NOT EXISTS - * FOR (u:User) ON (u.id); - * - * CREATE INDEX user_email_index IF NOT EXISTS - * FOR (u:User) ON (u.email); - * - * CREATE CONSTRAINT session_session_token_constraint IF NOT EXISTS - * ON (s:Session) ASSERT s.sessionToken IS UNIQUE; - * - * CREATE INDEX session_session_token_index IF NOT EXISTS - * FOR (s:Session) ON (s.sessionToken); - * ``` - * - * 2. Indexes - * - * 2.1. For Community Edition **only** create single-property indexes - * - * ```sql - * CREATE INDEX account_provider_index IF NOT EXISTS - * FOR (a:Account) ON (a.provider); - * - * CREATE INDEX account_provider_account_id_index IF NOT EXISTS - * FOR (a:Account) ON (a.providerAccountId); - * - * CREATE INDEX verification_token_identifier_index IF NOT EXISTS - * FOR (v:VerificationToken) ON (v.identifier); - * - * CREATE INDEX verification_token_token_index IF NOT EXISTS - * FOR (v:VerificationToken) ON (v.token); - * ``` - * - * 2.2. For Enterprise Edition **only** create composite node key constraints and indexes - * - * ```sql - * CREATE CONSTRAINT account_provider_composite_constraint IF NOT EXISTS - * ON (a:Account) ASSERT (a.provider, a.providerAccountId) IS NODE KEY; - * - * CREATE INDEX account_provider_composite_index IF NOT EXISTS - * FOR (a:Account) ON (a.provider, a.providerAccountId); - * - * CREATE CONSTRAINT verification_token_composite_constraint IF NOT EXISTS - * ON (v:VerificationToken) ASSERT (v.identifier, v.token) IS NODE KEY; - * - * CREATE INDEX verification_token_composite_index IF NOT EXISTS - * FOR (v:VerificationToken) ON (v.identifier, v.token); - * ``` - * - */ export function Neo4jAdapter(session: Session): Adapter { const { read, write } = client(session) diff --git a/packages/adapter-pg/src/index.ts b/packages/adapter-pg/src/index.ts index c17c3bf037..f1ec092f3e 100644 --- a/packages/adapter-pg/src/index.ts +++ b/packages/adapter-pg/src/index.ts @@ -1,8 +1,8 @@ /** *
- *

An official PostgreSQL adapter for Auth.js / NextAuth.js.

+ *

An official PostgreSQL adapter for Auth.js / NextAuth.js.

* - * + * * *
* @@ -31,83 +31,6 @@ export function mapExpiresAt(account: any): any { } } -/** - * ## Setup - * - * The SQL schema for the tables used by this adapter is as follows. Learn more about the models at our doc page on [Database Models](https://authjs.dev/getting-started/database#models). - * - * ```sql - * CREATE TABLE verification_token ( - * identifier TEXT NOT NULL, - * expires TIMESTAMPTZ NOT NULL, - * token TEXT NOT NULL, - * - * PRIMARY KEY (identifier, token) - * ); - * - * CREATE TABLE accounts ( - * id SERIAL, - * "userId" INTEGER NOT NULL, - * type VARCHAR(255) NOT NULL, - * provider VARCHAR(255) NOT NULL, - * "providerAccountId" VARCHAR(255) NOT NULL, - * refresh_token TEXT, - * access_token TEXT, - * expires_at BIGINT, - * id_token TEXT, - * scope TEXT, - * session_state TEXT, - * token_type TEXT, - * - * PRIMARY KEY (id) - * ); - * - * CREATE TABLE sessions ( - * id SERIAL, - * "userId" INTEGER NOT NULL, - * expires TIMESTAMPTZ NOT NULL, - * "sessionToken" VARCHAR(255) NOT NULL, - * - * PRIMARY KEY (id) - * ); - * - * CREATE TABLE users ( - * id SERIAL, - * name VARCHAR(255), - * email VARCHAR(255), - * "emailVerified" TIMESTAMPTZ, - * image TEXT, - * - * PRIMARY KEY (id) - * ); - * ``` - * - * ```ts title="auth.ts" - * import NextAuth from "next-auth" - * import GoogleProvider from "next-auth/providers/google" - * import PostgresAdapter from "@auth/pg-adapter" - * import { Pool } from 'pg' - * - * const pool = new Pool({ - * host: 'localhost', - * user: 'database-user', - * max: 20, - * idleTimeoutMillis: 30000, - * connectionTimeoutMillis: 2000, - * }) - * - * export default NextAuth({ - * adapter: PostgresAdapter(pool), - * providers: [ - * GoogleProvider({ - * clientId: process.env.GOOGLE_CLIENT_ID, - * clientSecret: process.env.GOOGLE_CLIENT_SECRET, - * }), - * ], - * }) - * ``` - * - */ export default function PostgresAdapter(client: Pool): Adapter { return { async createVerificationToken( diff --git a/packages/adapter-pouchdb/src/index.ts b/packages/adapter-pouchdb/src/index.ts index e1d8c37436..6c2d864fcb 100644 --- a/packages/adapter-pouchdb/src/index.ts +++ b/packages/adapter-pouchdb/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

Official PouchDB adapter for Auth.js / NextAuth.js.

+ *

Official PouchDB adapter for Auth.js / NextAuth.js.

* * * @@ -82,59 +82,6 @@ export interface PouchDBAdapterOptions { indexes?: IndexConfig } -/** - * :::info - * Depending on your architecture you can use PouchDB's http adapter to reach any database compliant with the CouchDB protocol (CouchDB, Cloudant, etc.) or use any other PouchDB compatible adapter (leveldb, in-memory, etc.) - * ::: - * - * ## Setup - * - * :::note - * Your PouchDB instance MUST provide the `pouchdb-find` plugin since it is used internally by the adapter to build and manage indexes - * ::: - * - * Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object: - * - * ```js title="pages/api/auth/[...nextauth].js" - * import NextAuth from "next-auth" - * import GoogleProvider from "next-auth/providers/google" - * import { PouchDBAdapter } from "@auth/pouchdb-adapter" - * import PouchDB from "pouchdb" - * - * // Setup your PouchDB instance and database - * PouchDB - * .plugin(require("pouchdb-adapter-leveldb")) // Or any other adapter - * .plugin(require("pouchdb-find")) // Don't forget the `pouchdb-find` plugin - * - * const pouchdb = new PouchDB("auth_db", { adapter: "leveldb" }) - * - * // For more information on each option (and a full list of options) go to - * // https://authjs.dev/reference/core/types#authconfig - * export default NextAuth({ - * // https://authjs.dev/getting-started/authentication/oauth - * providers: [ - * GoogleProvider({ - * clientId: process.env.GOOGLE_ID, - * clientSecret: process.env.GOOGLE_SECRET, - * }), - * ], - * adapter: PouchDBAdapter(pouchdb), - * }) - * ``` - * - * ## Advanced usage - * - * ### Memory-First Caching Strategy - * - * If you need to boost your authentication layer performance, you may use PouchDB's powerful sync features and various adapters, to build a memory-first caching strategy. - * - * Use an in-memory PouchDB as your main authentication database, and synchronize it with any other persisted PouchDB. You may do a one way, one-off replication at startup from the persisted PouchDB into the in-memory PouchDB, then two-way, continuous sync. - * - * This will most likely not increase performance much in a serverless environment due to various reasons such as concurrency, function startup time increases, etc. - * - * For more details, please see https://pouchdb.com/api.html#sync - * - */ export function PouchDBAdapter(options: PouchDBAdapterOptions): Adapter { const { pouchdb } = options const { diff --git a/packages/adapter-sequelize/src/index.ts b/packages/adapter-sequelize/src/index.ts index bebcc6744a..701d9a08b2 100644 --- a/packages/adapter-sequelize/src/index.ts +++ b/packages/adapter-sequelize/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

Official Sequilize adapter for Auth.js / NextAuth.js.

+ *

Official Sequilize adapter for Auth.js / NextAuth.js.

* * * @@ -58,83 +58,6 @@ export interface SequelizeAdapterOptions { }> } -/** - * :::warning - * You'll also have to manually install [the driver for your database](https://sequelize.org/master/manual/getting-started.html) of choice. - * ::: - * - * ## Setup - * - * ### Configuring Auth.js - * - * Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object. - * - * ```js title="pages/api/auth/[...nextauth].js" - * import NextAuth from "next-auth" - * import SequelizeAdapter from "@auth/sequelize-adapter" - * import { Sequelize } from "sequelize" - * - * // https://sequelize.org/master/manual/getting-started.html#connecting-to-a-database - * const sequelize = new Sequelize("yourconnectionstring") - * - * // For more information on each option (and a full list of options) go to - * // https://authjs.dev/reference/core#authconfig - * export default NextAuth({ - * // https://authjs.dev/reference/providers/ - * providers: [], - * adapter: SequelizeAdapter(sequelize), - * }) - * ``` - * - * ### Updating the database schema - * - * By default, the sequelize adapter will not create tables in your database. In production, best practice is to create the [required tables](https://authjs.dev/reference/core/adapters#models) in your database via [migrations](https://sequelize.org/master/manual/migrations.html). In development, you are able to call [`sequelize.sync()`](https://sequelize.org/master/manual/model-basics.html#model-synchronization) to have sequelize create the necessary tables, foreign keys and indexes: - * - * > This schema is adapted for use in Sequelize and based upon our main [schema](https://authjs.dev/reference/core/adapters#models) - * - * ```js - * import NextAuth from "next-auth" - * import SequelizeAdapter from "@auth/sequelize-adapter" - * import Sequelize from 'sequelize' - * - * const sequelize = new Sequelize("sqlite::memory:") - * const adapter = SequelizeAdapter(sequelize) - * - * // Calling sync() is not recommended in production - * sequelize.sync() - * - * export default NextAuth({ - * adapter - * }) - * ``` - * - * ## Advanced usage - * - * ### Using custom models - * - * Sequelize models are option to customization like so: - * - * ```js - * import NextAuth from "next-auth" - * import SequelizeAdapter, { models } from "@auth/sequelize-adapter" - * import Sequelize, { DataTypes } from "sequelize" - * - * const sequelize = new Sequelize("sqlite::memory:") - * - * export default NextAuth({ - * // https://authjs.dev/reference/providers/ - * providers: [], - * adapter: SequelizeAdapter(sequelize, { - * models: { - * User: sequelize.define("user", { - * ...models.User, - * phoneNumber: DataTypes.STRING, - * }), - * }, - * }), - * }) - * ``` - */ export default function SequelizeAdapter( client: Sequelize, options?: SequelizeAdapterOptions diff --git a/packages/adapter-supabase/src/index.ts b/packages/adapter-supabase/src/index.ts index d94faffc7f..54f96e336a 100644 --- a/packages/adapter-supabase/src/index.ts +++ b/packages/adapter-supabase/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

Official Supabase adapter for Auth.js / NextAuth.js.

+ *

Official Supabase adapter for Auth.js / NextAuth.js.

* * * @@ -56,294 +56,6 @@ export interface SupabaseAdapterOptions { secret: string } -/** - * :::note - * This adapter is developed by the community and not officially maintained or supported by Supabase. It uses the Supabase Database to store user and session data in a separate `next_auth` schema. It is a standalone Auth server that does not interface with Supabase Auth and therefore provides a different feature set. - * - * If you're looking for an officially maintained Auth server with additional features like [built-in email server](https://supabase.com/docs/guides/auth/auth-email#configure-email-settings?utm_source=authjs-docs&medium=referral&campaign=authjs), [phone auth](https://supabase.com/docs/guides/auth/auth-twilio?utm_source=authjs-docs&medium=referral&campaign=authjs), and [Multi Factor Authentication (MFA / 2FA)](https://supabase.com/contact/mfa?utm_source=authjs-docs&medium=referral&campaign=authjs), please use [Supabase Auth](https://supabase.com/auth) with the [Auth Helpers for Next.js](https://supabase.com/docs/guides/auth/auth-helpers/nextjs?utm_source=authjs-docs&medium=referral&campaign=authjs). - * ::: - * - * ## Setup - * - * ### Configure Auth.js - * - * Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object. - * - * ```js title="pages/api/auth/[...nextauth].js" - * import NextAuth from "next-auth" - * import { SupabaseAdapter } from "@auth/supabase-adapter" - * - * // For more information on each option (and a full list of options) go to - * // https://authjs.dev/reference/core#authconfig - * export default NextAuth({ - * // https://authjs.dev/reference/core/providers - * providers: [], - * adapter: SupabaseAdapter({ - * url: process.env.NEXT_PUBLIC_SUPABASE_URL, - * secret: process.env.SUPABASE_SERVICE_ROLE_KEY, - * }), - * }) - * ``` - * - * ### Create the NextAuth schema in Supabase - * - * Setup your database as described in our main [schema](https://authjs.dev/reference/core/adapters#models), by copying the SQL schema below in the Supabase [SQL Editor](https://app.supabase.com/project/_/sql). - * - * Alternatively you can select the NextAuth Quickstart card on the [SQL Editor page](https://app.supabase.com/project/_/sql), or [create a migration with the Supabase CLI](https://supabase.com/docs/guides/cli/local-development#database-migrations?utm_source=authjs-docs&medium=referral&campaign=authjs). - * - * ```sql - * -- - * -- Name: next_auth; Type: SCHEMA; - * -- - * CREATE SCHEMA next_auth; - * - * GRANT USAGE ON SCHEMA next_auth TO service_role; - * GRANT ALL ON SCHEMA next_auth TO postgres; - * - * -- - * -- Create users table - * -- - * CREATE TABLE IF NOT EXISTS next_auth.users - * ( - * id uuid NOT NULL DEFAULT uuid_generate_v4(), - * name text, - * email text, - * "emailVerified" timestamp with time zone, - * image text, - * CONSTRAINT users_pkey PRIMARY KEY (id), - * CONSTRAINT email_unique UNIQUE (email) - * ); - * - * GRANT ALL ON TABLE next_auth.users TO postgres; - * GRANT ALL ON TABLE next_auth.users TO service_role; - * - * --- uid() function to be used in RLS policies - * CREATE FUNCTION next_auth.uid() RETURNS uuid - * LANGUAGE sql STABLE - * AS $$ - * select - * coalesce( - * nullif(current_setting('request.jwt.claim.sub', true), ''), - * (nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'sub') - * )::uuid - * $$; - * - * -- - * -- Create sessions table - * -- - * CREATE TABLE IF NOT EXISTS next_auth.sessions - * ( - * id uuid NOT NULL DEFAULT uuid_generate_v4(), - * expires timestamp with time zone NOT NULL, - * "sessionToken" text NOT NULL, - * "userId" uuid, - * CONSTRAINT sessions_pkey PRIMARY KEY (id), - * CONSTRAINT sessionToken_unique UNIQUE ("sessionToken"), - * CONSTRAINT "sessions_userId_fkey" FOREIGN KEY ("userId") - * REFERENCES next_auth.users (id) MATCH SIMPLE - * ON UPDATE NO ACTION - * ON DELETE CASCADE - * ); - * - * GRANT ALL ON TABLE next_auth.sessions TO postgres; - * GRANT ALL ON TABLE next_auth.sessions TO service_role; - * - * -- - * -- Create accounts table - * -- - * CREATE TABLE IF NOT EXISTS next_auth.accounts - * ( - * id uuid NOT NULL DEFAULT uuid_generate_v4(), - * type text NOT NULL, - * provider text NOT NULL, - * "providerAccountId" text NOT NULL, - * refresh_token text, - * access_token text, - * expires_at bigint, - * token_type text, - * scope text, - * id_token text, - * session_state text, - * oauth_token_secret text, - * oauth_token text, - * "userId" uuid, - * CONSTRAINT accounts_pkey PRIMARY KEY (id), - * CONSTRAINT provider_unique UNIQUE (provider, "providerAccountId"), - * CONSTRAINT "accounts_userId_fkey" FOREIGN KEY ("userId") - * REFERENCES next_auth.users (id) MATCH SIMPLE - * ON UPDATE NO ACTION - * ON DELETE CASCADE - * ); - * - * GRANT ALL ON TABLE next_auth.accounts TO postgres; - * GRANT ALL ON TABLE next_auth.accounts TO service_role; - * - * -- - * -- Create verification_tokens table - * -- - * CREATE TABLE IF NOT EXISTS next_auth.verification_tokens - * ( - * identifier text, - * token text, - * expires timestamp with time zone NOT NULL, - * CONSTRAINT verification_tokens_pkey PRIMARY KEY (token), - * CONSTRAINT token_unique UNIQUE (token), - * CONSTRAINT token_identifier_unique UNIQUE (token, identifier) - * ); - * - * GRANT ALL ON TABLE next_auth.verification_tokens TO postgres; - * GRANT ALL ON TABLE next_auth.verification_tokens TO service_role; - * ``` - * - * ### Expose the NextAuth schema in Supabase - * - * Expose the `next_auth` schema via the Serverless API in the [API settings](https://app.supabase.com/project/_/settings/api) by adding `next_auth` to the "Exposed schemas" list. - * - * When developing locally add `next_auth` to the `schemas` array in the `config.toml` file in the `supabase` folder that was generated by the [Supabase CLI](https://supabase.com/docs/guides/cli/local-development#initialize-your-project?utm_source=authjs-docs&medium=referral&campaign=authjs). - * - * ## Advanced usage - * - * ### Enabling Row Level Security (RLS) - * - * Postgres provides a powerful feature called [Row Level Security (RLS)](https://supabase.com/docs/guides/auth/row-level-security?utm_source=authjs-docs&medium=referral&campaign=authjs) to limit access to data. - * - * This works by sending a signed JWT to your [Supabase Serverless API](https://supabase.com/docs/guides/api?utm_source=authjs-docs&medium=referral&campaign=authjs). There is two steps to make this work with NextAuth: - * - * #### Generate the Supabase `access_token` JWT in the session callback - * - * To sign the JWT use the `jsonwebtoken` package: - * - * ```bash npm2yarn - * npm install jsonwebtoken - * ``` - * - * Using the [NexthAuth.js Session callback](https://authjs.dev/reference/core/types#session) create the Supabase `access_token` and append it to the `session` object. - * - * To sign the JWT use the Supabase JWT secret which can be found in the [API settings](https://app.supabase.com/project/_/settings/api) - * - * ```js title="pages/api/auth/[...nextauth].js" - * import NextAuth from "next-auth" - * import { SupabaseAdapter } from "@auth/supabase-adapter" - * import jwt from "jsonwebtoken" - * - * // For more information on each option (and a full list of options) go to - * // https://authjs.dev/reference/core/types#authconfig - * export default NextAuth({ - * // https://authjs.dev/getting-started/authentication/oauth - * providers: [], - * adapter: SupabaseAdapter({ - * url: process.env.NEXT_PUBLIC_SUPABASE_URL, - * secret: process.env.SUPABASE_SERVICE_ROLE_KEY, - * }), - * callbacks: { - * async session({ session, user }) { - * const signingSecret = process.env.SUPABASE_JWT_SECRET - * if (signingSecret) { - * const payload = { - * aud: "authenticated", - * exp: Math.floor(new Date(session.expires).getTime() / 1000), - * sub: user.id, - * email: user.email, - * role: "authenticated", - * } - * session.supabaseAccessToken = jwt.sign(payload, signingSecret) - * } - * return session - * }, - * }, - * }) - * ``` - * - * #### Inject the Supabase `access_token` JWT into the client - * - * For example, given the following public schema: - * - * ```sql - * -- Note: This table contains user data. Users should only be able to view and update their own data. - * create table users ( - * -- UUID from next_auth.users - * id uuid not null primary key, - * name text, - * email text, - * image text, - * constraint "users_id_fkey" foreign key ("id") - * references next_auth.users (id) match simple - * on update no action - * on delete cascade -- if a user is deleted in NextAuth they will also be deleted in our public table. - * ); - * alter table users enable row level security; - * create policy "Can view own user data." on users for select using (next_auth.uid() = id); - * create policy "Can update own user data." on users for update using (next_auth.uid() = id); - * - * -- This trigger automatically creates a user entry when a new user signs up via NextAuth. - * create function public.handle_new_user() - * returns trigger as $$ - * begin - * insert into public.users (id, name, email, image) - * values (new.id, new.name, new.email, new.image); - * return new; - * end; - * $$ language plpgsql security definer; - * create trigger on_auth_user_created - * after insert on next_auth.users - * for each row execute procedure public.handle_new_user(); - * ``` - * - * The `supabaseAccessToken` is now available on the `session` object and can be passed to the supabase-js client. This works in any environment: client-side, server-side (API routes, SSR), as well as in middleware edge functions! - * - * ```js - * // Use `useSession()` or `unstable_getServerSession()` to get the NextAuth session. - * - * const { supabaseAccessToken } = session - * - * const supabase = createClient( - * process.env.NEXT_PUBLIC_SUPABASE_URL, - * process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, - * { - * global: { - * headers: { - * Authorization: `Bearer ${supabaseAccessToken}`, - * }, - * }, - * } - * ) - * // Now you can query with RLS enabled. - * const { data, error } = await supabase.from("users").select("*") - * ``` - * - * ### Usage with TypeScript - * - * You can pass types that were generated with the Supabase CLI to the Supabase Client to get enhanced type safety and auto-completion. - * - * Creating a new supabase client object: - * - * ```tsx - * import { createClient } from "@supabase/supabase-js" - * import { Database } from "../database.types" - * - * const supabase = createClient() - * ``` - * - * #### Extend the session type with the `supabaseAccessToken` - * - * In order to extend the `session` object with the `supabaseAccessToken` we need to extend the `session` interface in a `types/next-auth.d.ts` file: - * - * ```ts title="types/next-auth.d.ts" - * import NextAuth, { DefaultSession } from "next-auth" - * - * declare module "next-auth" { - * // Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context - * interface Session { - * // A JWT which can be used as Authorization header with supabase-js for RLS. - * supabaseAccessToken?: string - * user: { - * // The user's postal address - * address: string - * } & DefaultSession["user"] - * } - * } - * ``` - */ export function SupabaseAdapter(options: SupabaseAdapterOptions): Adapter { const { url, secret } = options const supabase = createClient(url, secret, { diff --git a/packages/adapter-surrealdb/src/index.ts b/packages/adapter-surrealdb/src/index.ts index 56b6d91e75..2110b23d6e 100644 --- a/packages/adapter-surrealdb/src/index.ts +++ b/packages/adapter-surrealdb/src/index.ts @@ -1,8 +1,8 @@ /** *
- *

Official SurrealDB adapter for Auth.js / NextAuth.js.

+ *

Official SurrealDB adapter for Auth.js / NextAuth.js.

* - * + * * *
* @@ -118,89 +118,6 @@ export const toId = (surrealId: string) => { return surrealId.replace(/^⟨(.+)⟩$/, "$1") } -/** - * ## Setup - * - * The SurrealDB adapter does not handle connections automatically, so you will have to make sure that you pass the Adapter a `SurrealDBClient` that is connected already. Below you can see an example how to do this. - * - * ### Add the SurrealDB client - * - * #### Option 1/2 – Using RPC: - * - * ```js - * import { Surreal } from "surrealdb.js"; - * - * const connectionString = "http://0.0.0.0:8000" - * const username = "" - * const password = "" - * const namespace = "" - * const database = "" - * - * const clientPromise = new Promise(async (resolve, reject) => { - * const db = new Surreal(); - * try { - * await db.connect(`${connectionString}/rpc`, { - * namespace, - * database, - * auth: { username, password } - * }) - * resolve(db) - * } catch (e) { - * reject(e) - * } - * }) - * - * // Export a module-scoped MongoClient promise. By doing this in a - * // separate module, the client can be shared across functions. - * export default clientPromise - * ``` - * - * #### Option 2/2 – Using HTTP: - * - * Usefull in serverlees environments like Vercel. - * - * ```js - * import { ExperimentalSurrealHTTP } from "surrealdb.js" - * - * const connectionString = "http://0.0.0.0:8000" - * const username = "" - * const password = "" - * const namespace = "" - * const database = "" - * - * const clientPromise = new Promise>(async (resolve, reject) => { - * try { - * const db = new ExperimentalSurrealHTTP(connectionString, { - * fetch, - * namespace, - * database, - * auth: { username, password } - * }) - * resolve(db) - * } catch (e) { - * reject(e) - * } - * }) - * - * // Export a module-scoped MongoClient promise. By doing this in a - * // separate module, the client can be shared across functions. - * export default clientPromise - * ``` - * - * ### Configure Auth.js - * - * ```js - * import NextAuth from "next-auth" - * import { SurrealDBAdapter } from "@auth/surrealdb-adapter" - * import clientPromise from "../../../lib/surrealdb" - * - * // For more information on each option (and a full list of options) go to - * // https://authjs.dev/reference/providers/oauth - * export default NextAuth({ - * adapter: SurrealDBAdapter(clientPromise), - * }) - * ``` - **/ export function SurrealDBAdapter( client: Promise> // options = {} diff --git a/packages/adapter-typeorm/src/index.ts b/packages/adapter-typeorm/src/index.ts index 3e6b0c1c20..0cb2ad6f3f 100644 --- a/packages/adapter-typeorm/src/index.ts +++ b/packages/adapter-typeorm/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

Official TypeORM adapter for Auth.js / NextAuth.js.

+ *

Official TypeORM adapter for Auth.js / NextAuth.js.

* * * @@ -64,218 +64,6 @@ export async function getManager(options: { return manager } -/** - * ## Setup - * - * Configure Auth.js to use the TypeORM Adapter: - * - * ```ts title="pages/api/auth/[...nextauth].ts" - * import NextAuth from "next-auth" - * import { TypeORMAdapter } from "@auth/typeorm-adapter" - * - * export default NextAuth({ - * adapter: TypeORMAdapter("yourconnectionstring"), - * }) - * ``` - * - * `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 - * - * ### Custom models - * - * The TypeORM adapter uses [`Entity` classes](https://github.com/typeorm/typeorm/blob/master/docs/entities.md) to define the shape of your data. - * - * If you want to override the default entities (for example to add a `role` field to your `UserEntity`), you will have to do the following: - * - * 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/src/entities.ts)) - * - * ```ts title="lib/entities.ts" {37-38} - * import { - * Entity, - * PrimaryGeneratedColumn, - * Column, - * ManyToOne, - * OneToMany, - * ValueTransformer, - * } from "typeorm" - * - * const transformer: Record<"date" | "bigint", ValueTransformer> = { - * date: { - * from: (date: string | null) => date && new Date(parseInt(date, 10)), - * to: (date?: Date) => date?.valueOf().toString(), - * }, - * bigint: { - * from: (bigInt: string | null) => bigInt && parseInt(bigInt, 10), - * to: (bigInt?: number) => bigInt?.toString(), - * }, - * } - * - * @Entity({ name: "users" }) - * export class UserEntity { - * @PrimaryGeneratedColumn("uuid") - * id!: string - * - * @Column({ type: "varchar", nullable: true }) - * name!: string | null - * - * @Column({ type: "varchar", nullable: true, unique: true }) - * email!: string | null - * - * @Column({ type: "varchar", nullable: true, transformer: transformer.date }) - * emailVerified!: string | null - * - * @Column({ type: "varchar", nullable: true }) - * image!: string | null - * - * @Column({ type: "varchar", nullable: true }) - * role!: string | null - * - * @OneToMany(() => SessionEntity, (session) => session.userId) - * sessions!: SessionEntity[] - * - * @OneToMany(() => AccountEntity, (account) => account.userId) - * accounts!: AccountEntity[] - * } - * - * @Entity({ name: "accounts" }) - * export class AccountEntity { - * @PrimaryGeneratedColumn("uuid") - * id!: string - * - * @Column({ type: "uuid" }) - * userId!: string - * - * @Column() - * type!: string - * - * @Column() - * provider!: string - * - * @Column() - * providerAccountId!: string - * - * @Column({ type: "varchar", nullable: true }) - * refresh_token!: string | null - * - * @Column({ type: "varchar", nullable: true }) - * access_token!: string | null - * - * @Column({ - * nullable: true, - * type: "bigint", - * transformer: transformer.bigint, - * }) - * expires_at!: number | null - * - * @Column({ type: "varchar", nullable: true }) - * token_type!: string | null - * - * @Column({ type: "varchar", nullable: true }) - * scope!: string | null - * - * @Column({ type: "varchar", nullable: true }) - * id_token!: string | null - * - * @Column({ type: "varchar", nullable: true }) - * session_state!: string | null - * - * @Column({ type: "varchar", nullable: true }) - * oauth_token_secret!: string | null - * - * @Column({ type: "varchar", nullable: true }) - * oauth_token!: string | null - * - * @ManyToOne(() => UserEntity, (user) => user.accounts, { - * createForeignKeyConstraints: true, - * }) - * user!: UserEntity - * } - * - * @Entity({ name: "sessions" }) - * export class SessionEntity { - * @PrimaryGeneratedColumn("uuid") - * id!: string - * - * @Column({ unique: true }) - * sessionToken!: string - * - * @Column({ type: "uuid" }) - * userId!: string - * - * @Column({ transformer: transformer.date }) - * expires!: string - * - * @ManyToOne(() => UserEntity, (user) => user.sessions) - * user!: UserEntity - * } - * - * @Entity({ name: "verification_tokens" }) - * export class VerificationTokenEntity { - * @PrimaryGeneratedColumn("uuid") - * id!: string - * - * @Column() - * token!: string - * - * @Column() - * identifier!: string - * - * @Column({ transformer: transformer.date }) - * expires!: string - * } - * ``` - * - * 2. Pass them to `TypeORMAdapter` - * - * ```js title="pages/api/auth/[...nextauth].js" - * import NextAuth from "next-auth" - * import { TypeORMAdapter } from "@auth/typeorm-adapter" - * import * as entities from "lib/entities" - * - * export default NextAuth({ - * adapter: TypeORMAdapter("yourconnectionstring", { entities }) - * }) - * ``` - * - * :::tip Synchronize your database - * The `synchronize: true` option in TypeORM will generate SQL that exactly matches the entities. This will automatically apply any changes it finds in the entity model. This is a useful option in development. - * ::: - * - * :::warning Using synchronize in production - * The option `synchronize: true` should not be enabled against production databases as it may cause data loss if the configured schema does not match the expected schema! We recommend that you synchronize/migrate your production database at build-time. - * ::: - * - * ### Naming Conventions - * - * If mixed snake_case and camelCase column names are an issue for you and/or your underlying database system, we recommend using TypeORM's naming strategy feature to change the target field names. There is a package called `typeorm-naming-strategies` which includes a `snake_case` strategy which will translate the fields from how Auth.js expects them, to snake_case in the actual database. - * - * For example, you can add the naming convention option to the connection object in your NextAuth config. - * - * ```js title="pages/api/auth/[...nextauth].js" - * import NextAuth from "next-auth" - * import { TypeORMAdapter } from "@auth/typeorm-adapter" - * import { SnakeNamingStrategy } from 'typeorm-naming-strategies' - * import { ConnectionOptions } from "typeorm" - * - * const connection: ConnectionOptions = { - * type: "mysql", - * host: "localhost", - * port: 3306, - * username: "test", - * password: "test", - * database: "test", - * namingStrategy: new SnakeNamingStrategy() - * } - * - * export default NextAuth({ - * adapter: TypeORMAdapter(connection) - * }) - * ``` - * - */ export function TypeORMAdapter( dataSource: string | DataSourceOptions, options?: TypeORMAdapterOptions diff --git a/packages/adapter-unstorage/src/index.ts b/packages/adapter-unstorage/src/index.ts index f909ec8d42..27f39ff775 100644 --- a/packages/adapter-unstorage/src/index.ts +++ b/packages/adapter-unstorage/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

Official Unstorage adapter for Auth.js / NextAuth.js.

+ *

Official Unstorage adapter for Auth.js / NextAuth.js.

* * * @@ -101,80 +101,6 @@ export function hydrateDates(json: object) { }, {} as any) } -/** - * ## Setup - * - * Configure Auth.js to use the Unstorage Adapter. - * - * ```js title="pages/api/auth/[...nextauth].js" - * import NextAuth from "next-auth" - * import GoogleProvider from "next-auth/providers/google" - * import { UnstorageAdapter } from "@auth/unstorage-adapter" - * import { createStorage } from "unstorage"; - * - * const storage = createStorage(); - * - * export default NextAuth({ - * adapter: UnstorageAdapter(storage), - * providers: [ - * GoogleProvider({ - * clientId: process.env.GOOGLE_CLIENT_ID, - * clientSecret: process.env.GOOGLE_CLIENT_SECRET, - * }), - * ], - * }) - * ``` - * - * ## Advanced usage - * - * ### Using multiple apps with a single storage - * - * If you have multiple Auth.js connected apps using the same storage, you need different key prefixes for every app. - * - * You can change the prefixes by passing an `options` object as the second argument to the adapter factory function. - * - * The default values for this object are: - * - * ```js - * const defaultOptions = { - * baseKeyPrefix: "", - * accountKeyPrefix: "user:account:", - * accountByUserIdPrefix: "user:account:by-user-id:", - * emailKeyPrefix: "user:email:", - * sessionKeyPrefix: "user:session:", - * sessionByUserIdKeyPrefix: "user:session:by-user-id:", - * userKeyPrefix: "user:", - * verificationTokenKeyPrefix: "user:token:", - * authenticatorKeyPrefix: "authenticator:id:", - * authenticatorUserKeyPrefix: "authenticator:by-user-id:", - * } - * ``` - * - * Usually changing the `baseKeyPrefix` should be enough for this scenario, but for more custom setups, you can also change the prefixes of every single key. - * - * Example: - * - * ```js - * export default NextAuth({ - * adapter: UnstorageAdapter(storage, {baseKeyPrefix: "app2:"}) - * }) - * ``` - * - * ### Using getItemRaw/setItemRaw instead of getItem/setItem - * - * If you are using storage that supports JSON, you can make it use `getItemRaw/setItemRaw` instead of `getItem/setItem`. - * - * This is an experimental feature. Please check [unjs/unstorage#142](https://github.com/unjs/unstorage/issues/142) for more information. - * - * You can enable this functionality by passing `useItemRaw: true` (default: false) in the `options` object as the second argument to the adapter factory function. - * - * ```js - * export default NextAuth({ - * adapter: UnstorageAdapter(storage, {useItemRaw: true}) - * }) - * ``` - * - */ export function UnstorageAdapter( storage: Storage, options: UnstorageAdapterOptions = {} diff --git a/packages/adapter-upstash-redis/src/index.ts b/packages/adapter-upstash-redis/src/index.ts index 6f044768a7..656b401ee2 100644 --- a/packages/adapter-upstash-redis/src/index.ts +++ b/packages/adapter-upstash-redis/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

Official Upstash Redis adapter for Auth.js / NextAuth.js.

+ *

Official Upstash Redis adapter for Auth.js / NextAuth.js.

* * * @@ -83,64 +83,6 @@ export function hydrateDates(json: object) { }, {} as any) } -/** - * ## Setup - * - * Configure Auth.js to use the Upstash Redis Adapter: - * - * ```js title="pages/api/auth/[...nextauth].js" - * import NextAuth from "next-auth" - * import GoogleProvider from "next-auth/providers/google" - * import { UpstashRedisAdapter } from "@auth/upstash-redis-adapter" - * import upstashRedisClient from "@upstash/redis" - * - * const redis = upstashRedisClient( - * process.env.UPSTASH_REDIS_URL, - * process.env.UPSTASH_REDIS_TOKEN - * ) - * - * export default NextAuth({ - * adapter: UpstashRedisAdapter(redis), - * providers: [ - * GoogleProvider({ - * clientId: process.env.GOOGLE_CLIENT_ID, - * clientSecret: process.env.GOOGLE_CLIENT_SECRET, - * }), - * ], - * }) - * ``` - * - * ## Advanced usage - * - * ### Using multiple apps with a single Upstash Redis instance - * - * The Upstash free-tier allows for only one Redis instance. If you have multiple Auth.js connected apps using this instance, you need different key prefixes for every app. - * - * You can change the prefixes by passing an `options` object as the second argument to the adapter factory function. - * - * The default values for this object are: - * - * ```js - * const defaultOptions = { - * baseKeyPrefix: "", - * accountKeyPrefix: "user:account:", - * accountByUserIdPrefix: "user:account:by-user-id:", - * emailKeyPrefix: "user:email:", - * sessionKeyPrefix: "user:session:", - * sessionByUserIdKeyPrefix: "user:session:by-user-id:", - * userKeyPrefix: "user:", - * verificationTokenKeyPrefix: "user:token:", - * } - * ``` - * - * Usually changing the `baseKeyPrefix` should be enough for this scenario, but for more custom setups, you can also change the prefixes of every single key. - * - * ```js - * export default NextAuth({ - * adapter: UpstashRedisAdapter(redis, {baseKeyPrefix: "app2:"}) - * }) - * ``` - */ export function UpstashRedisAdapter( client: Redis, options: UpstashRedisAdapterOptions = {} diff --git a/packages/adapter-xata/src/index.ts b/packages/adapter-xata/src/index.ts index 2f9a4640ba..09cd813b86 100644 --- a/packages/adapter-xata/src/index.ts +++ b/packages/adapter-xata/src/index.ts @@ -1,6 +1,6 @@ /** *
- *

Official Xata adapter for Auth.js / NextAuth.js.

+ *

Official Xata adapter for Auth.js / NextAuth.js.

* * * @@ -30,222 +30,8 @@ */ import type { Adapter } from "@auth/core/adapters" - import type { XataClient } from "./xata" -/** - * ## Setup - * - * This adapter allows using Auth.js with Xata as a database to store users, sessions, and more. The preferred way to create a Xata project and use Xata databases is using the [Xata Command Line Interface (CLI)](https://docs.xata.io/cli/getting-started). - * - * The CLI allows generating a `XataClient` that will help you work with Xata in a safe way, and that this adapter depends on. - * - * When you're ready, let's create a new Xata project using our Auth.js schema that the Xata adapter can work with. To do that, copy and paste this schema file into your project's directory: - * - * ```json title="schema.json" - * { - * "tables": [ - * { - * "name": "nextauth_users", - * "columns": [ - * { - * "name": "email", - * "type": "email" - * }, - * { - * "name": "emailVerified", - * "type": "datetime" - * }, - * { - * "name": "name", - * "type": "string" - * }, - * { - * "name": "image", - * "type": "string" - * } - * ] - * }, - * { - * "name": "nextauth_accounts", - * "columns": [ - * { - * "name": "user", - * "type": "link", - * "link": { - * "table": "nextauth_users" - * } - * }, - * { - * "name": "type", - * "type": "string" - * }, - * { - * "name": "provider", - * "type": "string" - * }, - * { - * "name": "providerAccountId", - * "type": "string" - * }, - * { - * "name": "refresh_token", - * "type": "string" - * }, - * { - * "name": "access_token", - * "type": "string" - * }, - * { - * "name": "expires_at", - * "type": "int" - * }, - * { - * "name": "token_type", - * "type": "string" - * }, - * { - * "name": "scope", - * "type": "string" - * }, - * { - * "name": "id_token", - * "type": "text" - * }, - * { - * "name": "session_state", - * "type": "string" - * } - * ] - * }, - * { - * "name": "nextauth_verificationTokens", - * "columns": [ - * { - * "name": "identifier", - * "type": "string" - * }, - * { - * "name": "token", - * "type": "string" - * }, - * { - * "name": "expires", - * "type": "datetime" - * } - * ] - * }, - * { - * "name": "nextauth_users_accounts", - * "columns": [ - * { - * "name": "user", - * "type": "link", - * "link": { - * "table": "nextauth_users" - * } - * }, - * { - * "name": "account", - * "type": "link", - * "link": { - * "table": "nextauth_accounts" - * } - * } - * ] - * }, - * { - * "name": "nextauth_users_sessions", - * "columns": [ - * { - * "name": "user", - * "type": "link", - * "link": { - * "table": "nextauth_users" - * } - * }, - * { - * "name": "session", - * "type": "link", - * "link": { - * "table": "nextauth_sessions" - * } - * } - * ] - * }, - * { - * "name": "nextauth_sessions", - * "columns": [ - * { - * "name": "sessionToken", - * "type": "string" - * }, - * { - * "name": "expires", - * "type": "datetime" - * }, - * { - * "name": "user", - * "type": "link", - * "link": { - * "table": "nextauth_users" - * } - * } - * ] - * } - * ] - * } - * ``` - * - * Now, run the following command: - * - * ```bash - * xata init --schema=./path/to/your/schema.json - * ``` - * - * 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. - * - * ```ts title="pages/api/auth/[...nextauth].ts" - * import NextAuth from "next-auth" - * import GoogleProvider from "next-auth/providers/google" - * - * const client = new XataClient() - * - * export default NextAuth({ - * providers: [ - * GoogleProvider({ - * clientId: process.env.GOOGLE_CLIENT_ID, - * clientSecret: process.env.GOOGLE_CLIENT_SECRET, - * }), - * ], - * }) - * ``` - * - * Now to Xata-fy this route, let's add the Xata client and adapter: - * - * ```diff - * import NextAuth from "next-auth" - * import GoogleProvider from "next-auth/providers/google" - * + import { XataAdapter } from "@auth/xata-adapter" - * + import { XataClient } from "../../../xata" // or wherever you've chosen to create the client - * - * + const client = new XataClient() - * - * export default NextAuth({ - * + adapter: XataAdapter(client), - * providers: [ - * GoogleProvider({ - * clientId: process.env.GOOGLE_CLIENT_ID, - * clientSecret: process.env.GOOGLE_CLIENT_SECRET, - * }), - * ], - * }) - * ``` - * - * This fully sets up your Auth.js app to work with Xata. - */ export function XataAdapter(client: XataClient): Adapter { return { async createUser(user) { diff --git a/packages/core/test/e2e/basic-auth.spec.ts b/packages/core/test/e2e/basic-auth.spec.ts index fc33bf9559..681e082c9f 100644 --- a/packages/core/test/e2e/basic-auth.spec.ts +++ b/packages/core/test/e2e/basic-auth.spec.ts @@ -14,10 +14,6 @@ test.describe("Basic Auth", () => { user: { email: "test@example.com", name: "Test User", - sub: expect.any(String), - iat: expect.any(Number), - exp: expect.any(Number), - jti: expect.any(String), }, expires: expect.any(String), }) @@ -58,11 +54,7 @@ test.describe("Basic Auth", () => { user: { email: "bob@alice.com", name: "Bob Alice", - picture: "https://avatars.githubusercontent.com/u/67470890?s=200&v=4", - sub: expect.any(String), - iat: expect.any(Number), - exp: expect.any(Number), - jti: expect.any(String), + image: "https://avatars.githubusercontent.com/u/67470890?s=200&v=4", }, expires: expect.any(String), })