Compare commits

..

51 Commits

Author SHA1 Message Date
GitHub Actions
ea65134a84 chore(release): bump package version(s) [skip ci] 2023-09-16 04:30:21 +00:00
Thang Vu
016b22833c chore(docs): add EdgeDB in typedoc 2023-09-16 11:21:48 +07:00
Bruno Crosier
67dbbb2cdf feat(adapters): new EdgeDB Adapter (#5781)
* init adapter folder

* add schema

* run migration

* run `npx @edgedb/generate edgeql-js`

* fix `generate` script

* add `EdgeDBAdapter`

* add tests

* add README

* docs

* dev app

* lockfile

* remove generated files

* ignore `dbschema/edgeql-js`

* add `postinstall` generate script

* update docs

* move `nonrecursive_access_policies` to default schema

* newlines

* remove js generation

* rewrite in edgeql

* make `userId` computed

* fix `createUser` image param

* code review comments

* update lockfile

* code review

* comments

* delete

* types

* revert settings.json

* delete migrations

* deps

* clean up

* Restore packages/adapter-test/index.ts

* chore: formatting & fix logic of useVerificationToken

* chore: delete .md file

* fix: test

* chore: logo

* chore: formatting

* chore: add edgedb to doc

---------

Co-authored-by: Nico Domino <yo@ndo.dev>
Co-authored-by: Thang Vu <hi@thvu.dev>
2023-09-16 11:03:48 +07:00
Dewin Umana
f87e66f0b3 feat(providers): TikTok provider (#8131)
* feat(providers): TikTok provider

* Linting

* Move files under the correct paths

* Added Tiktok Provider

* Update Bug provider template
2023-09-15 12:14:44 +07:00
k8pai
b1c46809f5 fix(docs): remove typesafety statements as string (#8566)
Removed typesafety statement `as string` from Configuring Auth.js of /adapter-dynamodb
2023-09-12 14:42:25 +02:00
Thang Vu
b9e9722b74 feat(providers): Dribbble provider (#8531)
* feat(providers): add Dribbble provider

* update Dribbble

Co-Authored-By: Pavel Fomchenkov <hello@pavel.codes>

---------

Co-authored-by: Pavel Fomchenkov <hello@pavel.codes>
2023-09-09 14:07:24 +07:00
GitHub Actions
57f75c7839 chore(release): bump package version(s) [skip ci] 2023-09-07 15:59:48 +00:00
Jonas Strassel
e20eb5b583 feat: bump mongodb to v6 (#8492)
BREAKING CHANGE:

The required minimum version of `mongodb` has been bumped to v6, make sure to upgrade it in your project via `npm i mongodb@latest` or the equivalent
2023-09-07 17:54:16 +02:00
Thang Vu
fb7c5f9ef6 feat: Mastodon Provider (#8516)
Co-authored-by: Leif Arriens <30775450+leifarriens@users.noreply.github.com>
2023-09-07 22:18:11 +07:00
Anthony Shew
e986369906 docs: Add more detail to Credentials provider. (#8482)
* Soften messaging on Credentials provider documentation.

* Get rid of the swap.

* Switch to using authorize().
2023-09-06 00:24:27 +02:00
Antonio Basile
f3c64a85c9 feat(providers): Click up provider (#8489)
* feat: click up provider created

* docs: ClickUp documentation

* Format

---------

Co-authored-by: Antonio Basile <antoniobasile2@eng.it>
Co-authored-by: Thang Vu <hi@thvu.dev>
2023-09-05 22:13:56 +07:00
GitHub Actions
4f3241f8dd chore(release): bump package version(s) [skip ci] 2023-09-04 23:02:35 +00:00
Jason
65043ba471 fix: return Session from deleteSession() (#8484)
Co-authored-by: Balázs Orbán <info@balazsorban.com>
2023-09-04 16:17:48 +02:00
Balázs Orbán
46c5a97a0e chore: add passage issuer 2023-09-03 13:24:03 +02:00
Balázs Orbán
9f99066b19 chore: update NextAuth.js example to use App Router (#8477)
* move initiaization to App Router

* add more providers

* don't use default export

* update tsconfig

* move under api

* add more providers

* add issuer

* add issuer
2023-09-03 11:59:58 +01:00
Menushka Weeratunga
e266001c28 docs: Add SvelteKit OAuth tutorial docs (#8311)
Co-authored-by: Thang Vu <hi@thvu.dev>
2023-09-02 10:11:31 +07:00
Thang Vu
f1eb45f3c1 docs: Add callbacks example for Credential Provider 2023-09-02 09:40:31 +07:00
jonek
f621627914 fix(sveltekit): support custom base path properly (#8231)
* fix(sveltekit): support custom base path

* update server

---------

Co-authored-by: Thang Vu <hi@thvu.dev>
2023-09-02 00:03:22 +07:00
dependabot[bot]
2b6ad02bba chore(deps-dev): bump mongodb from 4.7.0 to 4.17.0 (#8461)
Bumps [mongodb](https://github.com/mongodb/node-mongodb-native) from 4.7.0 to 4.17.0.
- [Release notes](https://github.com/mongodb/node-mongodb-native/releases)
- [Changelog](https://github.com/mongodb/node-mongodb-native/blob/v4.17.0/HISTORY.md)
- [Commits](https://github.com/mongodb/node-mongodb-native/compare/v4.7.0...v4.17.0)

---
updated-dependencies:
- dependency-name: mongodb
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-01 13:14:49 +01:00
GitHub Actions
1a23e41bca chore(release): bump package version(s) [skip ci] 2023-09-01 12:13:47 +00:00
Balázs Orbán
9dfef763fc chore: bump pnpm 2023-09-01 13:54:59 +02:00
Balázs Orbán
f53c16a454 chore: fix supabase tests 2023-09-01 13:53:18 +02:00
Thang Vu
e999511a2e docs: add framework tabs in getting started & guide (#8470) 2023-09-01 13:45:16 +02:00
Rexford Essilfie
2707f9ebfe docs: fix failing docs build (#8463)
chore: lint azure-devops provider
2023-08-31 14:35:40 +01:00
Evgenii Perminov
35977bf132 fix(providers): Update type oidc for Linkedin (#8345)
* linked in provider options and profile update

* interface update

* removed unchecked property access

* unncessary async

* revert changes to v4

* fallback to default properties

* Update packages/core/src/providers/linkedin.ts

---------

Co-authored-by: Thang Vu <hi@thvu.dev>
2023-08-29 11:31:18 +07:00
Pavel Fomchenkov
578ff21d7e feat(providers): add Azure DevOps provider (#4698) 2023-08-27 20:50:59 +07:00
Balázs Orbán
ba238796b8 Merge branch 'main' of github.com:nextauthjs/next-auth 2023-08-25 11:56:22 +02:00
Balázs Orbán
56b27de3be docs: fix edit links for auto-generated pages 2023-08-25 11:56:18 +02:00
Ahmed Abdelbaset
0bc9b4fe5a docs: Correct a typo that is causing a broken link. (#8405)
fix broken link
2023-08-25 10:43:44 +01:00
Balázs Orbán
327061ce70 chore: revert typedoc 2023-08-25 11:39:11 +02:00
Balázs Orbán
2ed407d6a5 fix: allow Prisma v5 as peer dependency 2023-08-25 11:32:38 +02:00
Balázs Orbán
e743340612 chore: suppress TS warning in sveltekit 2023-08-25 11:26:20 +02:00
Balázs Orbán
5140857256 chore: fix deps, upgrade docs dependencies 2023-08-25 11:21:55 +02:00
Balázs Orbán
9c6f81308c chore: bump pnpm and typescript 2023-08-24 20:31:33 +02:00
JunChao
66184c55eb docs: change var to import to solve using https-proxy-agent have the error: "HttpsProxyAgent is not a constructor" (#8400)
Update corporate-proxy.md
2023-08-24 14:54:23 +02:00
Balázs Orbán
07599ba41d Merge branch 'main' of github.com:nextauthjs/next-auth 2023-08-24 11:20:49 +02:00
Balázs Orbán
c5fc3e66ad docs: rename @next-auth/* to @auth/* 2023-08-24 11:20:44 +02:00
Balázs Orbán
5dfec49ee8 chore: rename @next-auth/* packages to @auth/* 2023-08-24 11:18:04 +02:00
brunsten
b20182c5fe fix: handle trailing slash when parsing the url (#8383)
Co-authored-by: Marcus Brunsten <bruno@Marcuss-MacBook-Rd.local>
2023-08-22 15:59:52 +02:00
Balázs Orbán
a6d9459a64 chore: mention that no repro = convert to discussion 2023-08-21 10:28:01 +01:00
GitHub Actions
99035b98f9 chore(release): bump package version(s) [skip ci] 2023-08-18 08:13:39 +00:00
Balázs Orbán
fabb0525d1 fix(adapters): use built-in is() to identify db type (#8342)
* fix(adapters): use built-in `is()` to identify db type

* remove unused .then

* fix imports
2023-08-18 09:11:33 +01:00
GitHub Actions
28e4328704 chore(release): bump package version(s) [skip ci] 2023-08-14 14:46:10 +00:00
Balázs Orbán
7ff4d9d280 feat: allow raw response for lib authors 2023-08-14 16:39:11 +02:00
Balázs Orbán
26815f7621 docs: clean up roadmap 2023-08-12 12:50:31 +02:00
Balázs Orbán
fe2c3dc6bf docs: fix links, references, grammar 2023-08-12 12:23:17 +02:00
GitHub Actions
c53435af8a chore(release): bump package version(s) [skip ci] 2023-08-12 09:41:43 +00:00
Balázs Orbán
f29a1f2778 fix(release): include lib in package
Related issue #8299
2023-08-12 11:38:01 +02:00
Balázs Orbán
a4c3270307 chore(turbo): include lib in cache outputs
Closes #8299
2023-08-12 11:35:44 +02:00
GitHub Actions
645d003d49 chore(release): bump package version(s) [skip ci] 2023-08-11 11:31:12 +00:00
Balázs Orbán
3f296615c5 fix(providers): docs typo 2023-08-11 13:27:33 +02:00
144 changed files with 12621 additions and 7224 deletions

View File

@@ -11,7 +11,7 @@ body:
### Important :exclamation:
_Providing incorrect/insufficient information or skipping steps to reproduce the issue may result in closing the issue or converting to a discussion without further explanation._
_Providing incorrect/insufficient information or skipping steps to reproduce the issue will result in closing the issue and/or converting to a discussion without further explanation._
If you have a generic question specific to your project, it is best asked in Discussions under the [Questions category](https://github.com/nextauthjs/next-auth/discussions/new?category=Questions)
# Let's wait with this until adoption in other frameworks.

View File

@@ -31,14 +31,17 @@ body:
- "Authentik"
- "Azure Active Directory"
- "Azure Active Directory B2C"
- "Azure DevOps"
- "Battlenet"
- "Beyond Identity"
- "Box"
- "Bungie"
- "ClickUp"
- "Cognito"
- "Coinbase"
- "Descope"
- "Discord"
- "Dribbble"
- "Dropbox"
- "EVE Online"
- "Facebook"
@@ -57,6 +60,7 @@ body:
- "LinkedIn"
- "Mailchimp"
- "Mail.ru"
- "Mastodon"
- "Medium"
- "Naver"
- "Netlify"
@@ -72,6 +76,7 @@ body:
- "Slack"
- "Spotify"
- "Strava"
- "Tiktok"
- "Todoist"
- "Trakt"
- "Twitch"

View File

@@ -24,7 +24,6 @@ body:
- "@auth/dgraph-adapter"
- "@auth/drizzle-adapter"
- "@auth/dynamodb-adapter"
- "@auth/drizzle-adapter"
- "@auth/fauna-adapter"
- "@auth/firebase-adapter"
- "@auth/kysely-adapter"

View File

@@ -16,7 +16,6 @@ on:
description: Package name (npm)
options:
- "@auth/core"
- "@auth/nextjs"
- "@auth/dgraph-adapter"
- "@auth/drizzle-adapter"
- "@auth/dynamodb-adapter"

View File

@@ -59,6 +59,10 @@ WIKIMEDIA_SECRET=
YANDEX_ID=
YANDEX_SECRET=
# ClickUp OAuth. https://clickup.com/api/
CLICK_UP_ID=
CLICK_UP_SECRET=
# Example configuration for a Gmail account (will need SMTP enabled)
EMAIL_SERVER=smtps://user@gmail.com:password@smtp.gmail.com:465
EMAIL_FROM=user@gmail.com

View File

@@ -2,3 +2,4 @@ node_modules/
/test-results/
/playwright-report/
/playwright/.cache/
dbschema/edgeql-js

View File

@@ -0,0 +1,71 @@
module default {
type User {
property name -> str;
required property email -> str {
constraint exclusive;
}
property emailVerified -> datetime;
property image -> str;
multi link accounts := .<user[is Account];
multi link sessions := .<user[is Session];
property createdAt -> 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;

View File

@@ -0,0 +1,2 @@
[edgedb]
server-version = "2.6"

View File

@@ -15,11 +15,13 @@
"license": "ISC",
"dependencies": {
"@auth/core": "workspace:*",
"@auth/edgedb-adapter": "workspace:*",
"@auth/fauna-adapter": "workspace:*",
"@auth/prisma-adapter": "workspace:*",
"@auth/supabase-adapter": "workspace:*",
"@auth/typeorm-adapter": "workspace:*",
"@prisma/client": "^3",
"edgedb": "^1.0.1",
"@supabase/supabase-js": "^2.0.5",
"faunadb": "^4",
"next": "13.4.0",
@@ -29,6 +31,7 @@
"react-dom": "^18"
},
"devDependencies": {
"@edgedb/generate": "^0.0.4",
"@playwright/test": "1.29.2",
"@types/jsonwebtoken": "^8.5.5",
"@types/react": "18.0.37",

View File

@@ -39,7 +39,7 @@ import Yandex from "@auth/core/providers/yandex"
import Vk from "@auth/core/providers/vk"
import Wikimedia from "@auth/core/providers/wikimedia"
import WorkOS from "@auth/core/providers/workos"
import ClickUp from '@auth/core/providers/click-up'
// // Prisma
// import { PrismaClient } from "@prisma/client"
// import { PrismaAdapter } from "@auth/prisma-adapter"
@@ -71,6 +71,12 @@ import WorkOS from "@auth/core/providers/workos"
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
// })
// // EdgeDB
// import { EdgeDBAdapter } from "@auth/edgedb-adapter"
// import { createHttpClient } from "edgedb"
// const client = createHttpClient()
// const adapter = EdgeDBAdapter(client)
export const authConfig: AuthConfig = {
// adapter,
debug: process.env.NODE_ENV !== "production",
@@ -131,6 +137,7 @@ export const authConfig: AuthConfig = {
Vk({ clientId: process.env.VK_ID, clientSecret: process.env.VK_SECRET }),
Wikimedia({ clientId: process.env.WIKIMEDIA_ID, clientSecret: process.env.WIKIMEDIA_SECRET }),
WorkOS({ clientId: process.env.WORKOS_ID, clientSecret: process.env.WORKOS_SECRET }),
ClickUp({ clientId: process.env.CLICK_UP_ID, clientSecret: process.env.CLICK_UP_SECRET })
],
// debug: process.env.NODE_ENV !== "production",
}

View File

@@ -15,7 +15,7 @@
"@sveltejs/kit": "next",
"svelte": "3.55.0",
"svelte-check": "2.10.2",
"typescript": "4.9.4",
"typescript": "5.2.2",
"vite": "4.0.5"
},
"dependencies": {

View File

@@ -0,0 +1,5 @@
import NextAuth from "next-auth/next"
import { config } from "auth"
const handler = NextAuth(config)
export { handler as GET, handler as POST }

View File

@@ -0,0 +1,294 @@
import type { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from "next"
import type { NextAuthOptions as NextAuthConfig } from "next-auth"
import { getServerSession } from "next-auth"
import Apple from "next-auth/providers/apple"
import Atlassian from "next-auth/providers/atlassian"
import Auth0 from "next-auth/providers/auth0"
import Authentik from "next-auth/providers/authentik"
import AzureAD from "next-auth/providers/azure-ad"
import AzureB2C from "next-auth/providers/azure-ad-b2c"
import Battlenet from "next-auth/providers/battlenet"
import Box from "next-auth/providers/box"
import BoxyHQSAML from "next-auth/providers/boxyhq-saml"
import Bungie from "next-auth/providers/bungie"
import Cognito from "next-auth/providers/cognito"
import Coinbase from "next-auth/providers/coinbase"
import Discord from "next-auth/providers/discord"
import Dropbox from "next-auth/providers/dropbox"
import DuendeIDS6 from "next-auth/providers/duende-identity-server6"
import Eveonline from "next-auth/providers/eveonline"
import Facebook from "next-auth/providers/facebook"
import Faceit from "next-auth/providers/faceit"
import FortyTwoSchool from "next-auth/providers/42-school"
import Foursquare from "next-auth/providers/foursquare"
import Freshbooks from "next-auth/providers/freshbooks"
import Fusionauth from "next-auth/providers/fusionauth"
import GitHub from "next-auth/providers/github"
import Gitlab from "next-auth/providers/gitlab"
import Google from "next-auth/providers/google"
import Hubspot from "next-auth/providers/hubspot"
import Instagram from "next-auth/providers/instagram"
import Kakao from "next-auth/providers/kakao"
import Keycloak from "next-auth/providers/keycloak"
import Line from "next-auth/providers/line"
import LinkedIn from "next-auth/providers/linkedin"
import Mailchimp from "next-auth/providers/mailchimp"
import Mailru from "next-auth/providers/mailru"
import Medium from "next-auth/providers/medium"
import Naver from "next-auth/providers/naver"
import Netlify from "next-auth/providers/netlify"
import Okta from "next-auth/providers/okta"
import Onelogin from "next-auth/providers/onelogin"
import Osso from "next-auth/providers/osso"
import Osu from "next-auth/providers/osu"
import Passage from "next-auth/providers/passage"
import Patreon from "next-auth/providers/patreon"
import Pinterest from "next-auth/providers/pinterest"
import Pipedrive from "next-auth/providers/pipedrive"
import Reddit from "next-auth/providers/reddit"
import Salesforce from "next-auth/providers/salesforce"
import Slack from "next-auth/providers/slack"
import Spotify from "next-auth/providers/spotify"
import Strava from "next-auth/providers/strava"
import Todoist from "next-auth/providers/todoist"
import Trakt from "next-auth/providers/trakt"
import Twitch from "next-auth/providers/twitch"
import Twitter from "next-auth/providers/twitter"
import UnitedEffects from "next-auth/providers/united-effects"
import Vk from "next-auth/providers/vk"
import Wikimedia from "next-auth/providers/wikimedia"
import Wordpress from "next-auth/providers/wordpress"
import WorkOS from "next-auth/providers/workos"
import Yandex from "next-auth/providers/yandex"
import Zitadel from "next-auth/providers/zitadel"
import Zoho from "next-auth/providers/zoho"
import Zoom from "next-auth/providers/zoom"
// Read more at: https://next-auth.js.org/getting-started/typescript#module-augmentation
declare module "next-auth/jwt" {
interface JWT {
/** The user's role. */
userRole?: "admin"
}
}
export const config = {
// https://next-auth.js.org/configuration/providers/oauth
providers: [
Apple({ clientId: process.env.AUTH_APPLE_ID, clientSecret: process.env.AUTH_APPLE_SECRET }),
Atlassian({ clientId: process.env.AUTH_ATLASSIAN_ID, clientSecret: process.env.AUTH_ATLASSIAN_SECRET }),
Auth0({ clientId: process.env.AUTH_AUTH0_ID, clientSecret: process.env.AUTH_AUTH0_SECRET, issuer: process.env.AUTH_AUTH0_ISSUER }),
Authentik({ clientId: process.env.AUTH_AUTHENTIK_ID, clientSecret: process.env.AUTH_AUTHENTIK_SECRET }),
AzureAD({ clientId: process.env.AUTH_AZUREAD_ID, clientSecret: process.env.AUTH_AZUREAD_SECRET }),
AzureB2C({ clientId: process.env.AUTH_AZUREB2C_ID, clientSecret: process.env.AUTH_AZUREB2C_SECRET }),
Battlenet({ clientId: process.env.AUTH_BN_ID, clientSecret: process.env.AUTH_BN_SECRET, issuer: process.env.AUTH_BN_ISSUER }),
Box({ clientId: process.env.AUTH_BOX_ID, clientSecret: process.env.AUTH_BOX_SECRET }),
BoxyHQSAML({ clientId: process.env.AUTH_BOXYHQ_ID, clientSecret: process.env.AUTH_BOXYHQ_SECRET, issuer: process.env.AUTH_BOXYHQ_ISSUER }),
Bungie({ clientId: process.env.AUTH_BUNGIE_ID, clientSecret: process.env.AUTH_BUNGIE_SECRET }),
Cognito({ clientId: process.env.AUTH_COGNITO_ID, clientSecret: process.env.AUTH_COGNITO_SECRET }),
Coinbase({ clientId: process.env.AUTH_COINBASE_ID, clientSecret: process.env.AUTH_COINBASE_SECRET }),
Discord({ clientId: process.env.AUTH_DISCORD_ID, clientSecret: process.env.AUTH_DISCORD_SECRET }),
Dropbox({ clientId: process.env.AUTH_DROPBOX_ID, clientSecret: process.env.AUTH_DROPBOX_SECRET }),
DuendeIDS6({ clientId: process.env.AUTH_DUENDEIDS6_ID, clientSecret: process.env.AUTH_DUENDEIDS6_SECRET }),
Eveonline({ clientId: process.env.AUTH_EVEONLINE_ID, clientSecret: process.env.AUTH_EVEONLINE_SECRET }),
Facebook({ clientId: process.env.AUTH_FACEBOOK_ID, clientSecret: process.env.AUTH_FACEBOOK_SECRET }),
Faceit({ clientId: process.env.AUTH_FACEIT_ID, clientSecret: process.env.AUTH_FACEIT_SECRET }),
FortyTwoSchool({ clientId: process.env.AUTH_FORTYTWOSCHOOL_ID, clientSecret: process.env.AUTH_FORTYTWOSCHOOL_SECRET }),
Foursquare({ clientId: process.env.AUTH_FOURSQUARE_ID, clientSecret: process.env.AUTH_FOURSQUARE_SECRET }),
Freshbooks({ clientId: process.env.AUTH_FRESHBOOKS_ID, clientSecret: process.env.AUTH_FRESHBOOKS_SECRET }),
Fusionauth({ clientId: process.env.AUTH_FUSIONAUTH_ID, clientSecret: process.env.AUTH_FUSIONAUTH_SECRET }),
GitHub({ clientId: process.env.AUTH_GITHUB_ID, clientSecret: process.env.AUTH_GITHUB_SECRET }),
Gitlab({ clientId: process.env.AUTH_GITLAB_ID, clientSecret: process.env.AUTH_GITLAB_SECRET }),
Google({ clientId: process.env.AUTH_GOOGLE_ID, clientSecret: process.env.AUTH_GOOGLE_SECRET }),
Hubspot({ clientId: process.env.AUTH_HUBSPOT_ID, clientSecret: process.env.AUTH_HUBSPOT_SECRET }),
Instagram({ clientId: process.env.AUTH_INSTAGRAM_ID, clientSecret: process.env.AUTH_INSTAGRAM_SECRET }),
Kakao({ clientId: process.env.AUTH_KAKAO_ID, clientSecret: process.env.AUTH_KAKAO_SECRET }),
Keycloak({ clientId: process.env.AUTH_KEYCLOAK_ID, clientSecret: process.env.AUTH_KEYCLOAK_SECRET }),
Line({ clientId: process.env.AUTH_LINE_ID, clientSecret: process.env.AUTH_LINE_SECRET }),
LinkedIn({ clientId: process.env.AUTH_LINKEDIN_ID, clientSecret: process.env.AUTH_LINKEDIN_SECRET }),
Mailchimp({ clientId: process.env.AUTH_MAILCHIMP_ID, clientSecret: process.env.AUTH_MAILCHIMP_SECRET }),
Mailru({ clientId: process.env.AUTH_MAILRU_ID, clientSecret: process.env.AUTH_MAILRU_SECRET }),
Medium({ clientId: process.env.AUTH_MEDIUM_ID, clientSecret: process.env.AUTH_MEDIUM_SECRET }),
Naver({ clientId: process.env.AUTH_NAVER_ID, clientSecret: process.env.AUTH_NAVER_SECRET }),
Netlify({ clientId: process.env.AUTH_NETLIFY_ID, clientSecret: process.env.AUTH_NETLIFY_SECRET }),
Okta({ clientId: process.env.AUTH_OKTA_ID, clientSecret: process.env.AUTH_OKTA_SECRET }),
Onelogin({ clientId: process.env.AUTH_ONELOGIN_ID, clientSecret: process.env.AUTH_ONELOGIN_SECRET }),
Osso({ clientId: process.env.AUTH_OSSO_ID, clientSecret: process.env.AUTH_OSSO_SECRET, issuer: process.env.AUTH_OSSO_ISSUER }),
Osu({ clientId: process.env.AUTH_OSU_ID, clientSecret: process.env.AUTH_OSU_SECRET }),
Passage({ clientId: process.env.AUTH_PASSAGE_ID, clientSecret: process.env.AUTH_PASSAGE_SECRET, issuer: process.env.AUTH_PASSAGE_ISSUER }),
Patreon({ clientId: process.env.AUTH_PATREON_ID, clientSecret: process.env.AUTH_PATREON_SECRET }),
Pinterest({ clientId: process.env.AUTH_PINTEREST_ID, clientSecret: process.env.AUTH_PINTEREST_SECRET }),
Pipedrive({ clientId: process.env.AUTH_PIPEDRIVE_ID, clientSecret: process.env.AUTH_PIPEDRIVE_SECRET }),
Reddit({ clientId: process.env.AUTH_REDDIT_ID, clientSecret: process.env.AUTH_REDDIT_SECRET }),
Salesforce({ clientId: process.env.AUTH_SALESFORCE_ID, clientSecret: process.env.AUTH_SALESFORCE_SECRET }),
Slack({ clientId: process.env.AUTH_SLACK_ID, clientSecret: process.env.AUTH_SLACK_SECRET }),
Spotify({ clientId: process.env.AUTH_SPOTIFY_ID, clientSecret: process.env.AUTH_SPOTIFY_SECRET }),
Strava({ clientId: process.env.AUTH_STRAVA_ID, clientSecret: process.env.AUTH_STRAVA_SECRET }),
Todoist({ clientId: process.env.AUTH_TODOIST_ID, clientSecret: process.env.AUTH_TODOIST_SECRET }),
Trakt({ clientId: process.env.AUTH_TRAKT_ID, clientSecret: process.env.AUTH_TRAKT_SECRET }),
Twitch({ clientId: process.env.AUTH_TWITCH_ID, clientSecret: process.env.AUTH_TWITCH_SECRET }),
Twitter({ clientId: process.env.AUTH_TWITTER_ID, clientSecret: process.env.AUTH_TWITTER_SECRET, version: "2.0" }),
UnitedEffects({ clientId: process.env.AUTH_UE_ID, clientSecret: process.env.AUTH_UE_SECRET, issuer: process.env.AUTH_UE_ISSUER }),
Vk({ clientId: process.env.AUTH_VK_ID, clientSecret: process.env.AUTH_VK_SECRET }),
Wikimedia({ clientId: process.env.AUTH_WIKIMEDIA_ID, clientSecret: process.env.AUTH_WIKIMEDIA_SECRET }),
Wordpress({ clientId: process.env.AUTH_WORDPRESS_ID, clientSecret: process.env.AUTH_WORDPRESS_SECRET }),
WorkOS({ clientId: process.env.AUTH_WORKOS_ID, clientSecret: process.env.AUTH_WORKOS_SECRET }),
Yandex({ clientId: process.env.AUTH_YANDEX_ID, clientSecret: process.env.AUTH_YANDEX_SECRET }),
Zitadel({ clientId: process.env.AUTH_ZITADEL_ID, clientSecret: process.env.AUTH_ZITADEL_SECRET }),
Zoho({ clientId: process.env.AUTH_ZOHO_ID, clientSecret: process.env.AUTH_ZOHO_SECRET }),
Zoom({ clientId: process.env.AUTH_ZOOM_ID, clientSecret: process.env.AUTH_ZOOM_SECRET }),
],
callbacks: {
async jwt({ token }) {
token.userRole = "admin"
return token
},
},
} satisfies NextAuthConfig
// Helper function to get session without passing config every time
// https://next-auth.js.org/configuration/nextjs#getserversession
export function auth(...args: [GetServerSidePropsContext["req"], GetServerSidePropsContext["res"]] | [NextApiRequest, NextApiResponse] | []) {
return getServerSession(...args, config)
}
// We recommend doing your own environment variable validation
declare global {
namespace NodeJS {
export interface ProcessEnv {
NEXTAUTH_SECRET: string
AUTH_APPLE_ID: string
AUTH_APPLE_SECRET: string
AUTH_ATLASSIAN_ID: string
AUTH_ATLASSIAN_SECRET: string
AUTH_AUTH0_ID: string
AUTH_AUTH0_ISSUER: string
AUTH_AUTH0_SECRET: string
AUTH_AUTHENTIK_ID: string
AUTH_AUTHENTIK_SECRET: string
AUTH_AZUREAD_ID: string
AUTH_AZUREAD_SECRET: string
AUTH_AZUREB2C_ID: string
AUTH_AZUREB2C_SECRET: string
AUTH_BN_ID: string
AUTH_BN_ISSUER: any
AUTH_BN_SECRET: string
AUTH_BOX_ID: string
AUTH_BOX_SECRET: string
AUTH_BOXYHQ_ID: string
AUTH_BOXYHQ_ISSUER: string
AUTH_BOXYHQ_SECRET: string
AUTH_BUNGIE_ID: string
AUTH_BUNGIE_SECRET: string
AUTH_COGNITO_ID: string
AUTH_COGNITO_SECRET: string
AUTH_COINBASE_ID: string
AUTH_COINBASE_SECRET: string
AUTH_DISCORD_ID: string
AUTH_DISCORD_SECRET: string
AUTH_DROPBOX_ID: string
AUTH_DROPBOX_SECRET: string
AUTH_DUENDEIDS6_ID: string
AUTH_DUENDEIDS6_SECRET: string
AUTH_EVEONLINE_ID: string
AUTH_EVEONLINE_SECRET: string
AUTH_FACEBOOK_ID: string
AUTH_FACEBOOK_SECRET: string
AUTH_FACEIT_ID: string
AUTH_FACEIT_SECRET: string
AUTH_FORTYTWOSCHOOL_ID: string
AUTH_FORTYTWOSCHOOL_SECRET: string
AUTH_FOURSQUARE_ID: string
AUTH_FOURSQUARE_SECRET: string
AUTH_FRESHBOOKS_ID: string
AUTH_FRESHBOOKS_SECRET: string
AUTH_FUSIONAUTH_ID: string
AUTH_FUSIONAUTH_SECRET: string
AUTH_GITHUB_ID: string
AUTH_GITHUB_SECRET: string
AUTH_GITLAB_ID: string
AUTH_GITLAB_SECRET: string
AUTH_GOOGLE_ID: string
AUTH_GOOGLE_SECRET: string
AUTH_HUBSPOT_ID: string
AUTH_HUBSPOT_SECRET: string
AUTH_INSTAGRAM_ID: string
AUTH_INSTAGRAM_SECRET: string
AUTH_KAKAO_ID: string
AUTH_KAKAO_SECRET: string
AUTH_KEYCLOAK_ID: string
AUTH_KEYCLOAK_SECRET: string
AUTH_LINE_ID: string
AUTH_LINE_SECRET: string
AUTH_LINKEDIN_ID: string
AUTH_LINKEDIN_SECRET: string
AUTH_MAILCHIMP_ID: string
AUTH_MAILCHIMP_SECRET: string
AUTH_MAILRU_ID: string
AUTH_MAILRU_SECRET: string
AUTH_MEDIUM_ID: string
AUTH_MEDIUM_SECRET: string
AUTH_NAVER_ID: string
AUTH_NAVER_SECRET: string
AUTH_NETLIFY_ID: string
AUTH_NETLIFY_SECRET: string
AUTH_OKTA_ID: string
AUTH_OKTA_SECRET: string
AUTH_ONELOGIN_ID: string
AUTH_ONELOGIN_SECRET: string
AUTH_OSSO_ID: string
AUTH_OSSO_ISSUER: string
AUTH_OSSO_SECRET: string
AUTH_OSU_ID: string
AUTH_OSU_SECRET: string
AUTH_PASSAGE_ID: string
AUTH_PASSAGE_ISSUER: string
AUTH_PASSAGE_SECRET: string
AUTH_PATREON_ID: string
AUTH_PATREON_SECRET: string
AUTH_PINTEREST_ID: string
AUTH_PINTEREST_SECRET: string
AUTH_PIPEDRIVE_ID: string
AUTH_PIPEDRIVE_SECRET: string
AUTH_REDDIT_ID: string
AUTH_REDDIT_SECRET: string
AUTH_SALESFORCE_ID: string
AUTH_SALESFORCE_SECRET: string
AUTH_SLACK_ID: string
AUTH_SLACK_SECRET: string
AUTH_SPOTIFY_ID: string
AUTH_SPOTIFY_SECRET: string
AUTH_STRAVA_ID: string
AUTH_STRAVA_SECRET: string
AUTH_TODOIST_ID: string
AUTH_TODOIST_SECRET: string
AUTH_TRAKT_ID: string
AUTH_TRAKT_SECRET: string
AUTH_TWITCH_ID: string
AUTH_TWITCH_SECRET: string
AUTH_TWITTER_ID: string
AUTH_TWITTER_SECRET: string
AUTH_UE_ID: string
AUTH_UE_ISSUER: string
AUTH_UE_SECRET: string
AUTH_VK_ID: string
AUTH_VK_SECRET: string
AUTH_WIKIMEDIA_ID: string
AUTH_WIKIMEDIA_SECRET: string
AUTH_WORDPRESS_ID: string
AUTH_WORDPRESS_SECRET: string
AUTH_WORKOS_ID: string
AUTH_WORKOS_SECRET: string
AUTH_YANDEX_ID: string
AUTH_YANDEX_SECRET: string
AUTH_ZITADEL_ID: string
AUTH_ZITADEL_SECRET: string
AUTH_ZOHO_ID: string
AUTH_ZOHO_SECRET: string
AUTH_ZOOM_ID: string
AUTH_ZOOM_SECRET: string
}
}
}

View File

@@ -1,10 +0,0 @@
import "next-auth/jwt"
// Read more at: https://next-auth.js.org/getting-started/typescript#module-augmentation
declare module "next-auth/jwt" {
interface JWT {
/** The user's role. */
userRole?: "admin"
}
}

View File

@@ -26,6 +26,6 @@
"devDependencies": {
"@types/node": "^18.16.2",
"@types/react": "^18.2.0",
"typescript": "^5.0.4"
"typescript": "5.2.2"
}
}

View File

@@ -1,44 +0,0 @@
import NextAuth, { NextAuthOptions } from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import FacebookProvider from "next-auth/providers/facebook"
import GithubProvider from "next-auth/providers/github"
import TwitterProvider from "next-auth/providers/twitter"
import Auth0Provider from "next-auth/providers/auth0"
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export const authOptions: NextAuthOptions = {
// https://next-auth.js.org/configuration/providers/oauth
providers: [
Auth0Provider({
clientId: process.env.AUTH0_ID,
clientSecret: process.env.AUTH0_SECRET,
issuer: process.env.AUTH0_ISSUER,
}),
FacebookProvider({
clientId: process.env.FACEBOOK_ID,
clientSecret: process.env.FACEBOOK_SECRET,
}),
GithubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
TwitterProvider({
clientId: process.env.TWITTER_ID,
clientSecret: process.env.TWITTER_SECRET,
version: "2.0",
}),
],
callbacks: {
async jwt({ token }) {
token.userRole = "admin"
return token
},
},
}
export default NextAuth(authOptions)

View File

@@ -1,14 +1,13 @@
// This is an example of to protect an API route
import { getServerSession } from "next-auth/next"
import { authOptions } from "../auth/[...nextauth]"
import { auth } from "auth"
import type { NextApiRequest, NextApiResponse } from "next"
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const session = await getServerSession(req, res, authOptions)
const session = await auth(req, res)
if (session) {
return res.send({

View File

@@ -1,13 +1,12 @@
// This is an example of how to access a session from an API route
import { getServerSession } from "next-auth"
import { authOptions } from "../auth/[...nextauth]"
import { auth } from "auth"
import type { NextApiRequest, NextApiResponse } from "next"
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const session = await getServerSession(req, res, authOptions)
const session = await auth(req, res)
res.send(JSON.stringify(session, null, 2))
}

View File

@@ -1,5 +1,4 @@
import { getServerSession } from "next-auth/next"
import { authOptions } from "./api/auth/[...nextauth]"
import { auth } from "auth"
import Layout from "../components/layout"
import type { GetServerSidePropsContext } from "next"
@@ -36,9 +35,5 @@ export default function ServerSidePage() {
// Export the `session` prop to use sessions with Server Side Rendering
export async function getServerSideProps(context: GetServerSidePropsContext) {
return {
props: {
session: await getServerSession(context.req, context.res, authOptions),
},
}
return { props: { session: await auth(context.req, context.res) } }
}

View File

@@ -1,18 +0,0 @@
declare namespace NodeJS {
export interface ProcessEnv {
NEXTAUTH_URL: string
NEXTAUTH_SECRET: string
GITHUB_ID: string
GITHUB_SECRET: string
FACEBOOK_ID: string
FACEBOOK_SECRET: string
TWITTER_ID: string
TWITTER_SECRET: string
GOOGLE_ID: string
GOOGLE_SECRET: string
AUTH0_ID: string
AUTH0_SECRET: string
DESCOPE_ID: string
DESCOPE_SECRET: string
}
}

View File

@@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -13,14 +17,22 @@
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
"incremental": true,
"baseUrl": ".",
"plugins": [
{
"name": "next"
}
]
},
"include": [
"process.d.ts",
"next-env.d.ts",
"next-auth.d.ts",
"**/*.ts",
"**/*.tsx"
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": ["node_modules"]
"exclude": [
"node_modules"
]
}

View File

@@ -13,7 +13,7 @@
"solid-start-node": "^0.2.9",
"solid-start-vercel": "^0.2.9",
"tailwindcss": "^3.2.4",
"typescript": "^4.8.3",
"typescript": "5.2.2",
"vite": "^3.1.0"
},
"dependencies": {

View File

@@ -18,7 +18,7 @@
"@sveltejs/kit": "next",
"svelte": "3.55.0",
"svelte-check": "2.10.2",
"typescript": "4.9.4",
"typescript": "5.2.2",
"vite": "4.0.1"
},
"dependencies": {

View File

@@ -7,7 +7,7 @@ title: Frequently Asked Questions
### Is Auth.js commercial software?
Auth.js is an open source project built by individual contributors.
Auth.js is an open-source project built by individual contributors.
It is not commercial software and is not associated with a commercial organization.
@@ -17,7 +17,7 @@ It is not commercial software and is not associated with a commercial organizati
<details>
<summary>
<h3 style={{display:"inline-block"}}>What databases does Auth.js support?</h3>
<h3 style={{display: "inline-block"}}>What databases does Auth.js support?</h3>
</summary>
<p>
@@ -30,7 +30,7 @@ You can use also Auth.js with any database using a custom database adapter, or b
<details>
<summary>
<h3 style={{display:"inline-block"}}>What authentication services does Auth.js support?</h3>
<h3 style={{display: "inline-block"}}>What authentication services does Auth.js support?</h3>
</summary>
<p>
@@ -38,16 +38,16 @@ You can use also Auth.js with any database using a custom database adapter, or b
(See also: <a href="/reference/providers/oauth-builtin">Providers</a>)
</p>
Auth.js also supports email for passwordless sign in, which is useful for account recovery or for people who are not able to use an account with the configured OAuth services (e.g. due to service outage, account suspension or otherwise becoming locked out of an account).
Auth.js also supports email for passwordless sign-in, which is useful for account recovery or for people who are not able to use an account with the configured OAuth services (e.g. due to service outage, account suspension or otherwise becoming locked out of an account).
You can also use a custom based provider to support signing in with a username and password stored in an external database and/or using two factor authentication.
You can also use a custom-based provider to support signing in with a username and password stored in an external database and/or using two-factor authentication.
</p>
</details>
<details>
<summary>
<h3 style={{display:"inline-block"}}>Does Auth.js support signing in with a username and password?</h3>
<h3 style={{display: "inline-block"}}>Does Auth.js support signing in with a username and password?</h3>
</summary>
<p>
@@ -55,44 +55,44 @@ Auth.js is designed to avoid the need to store passwords for user accounts.
If you have an existing database of usernames and passwords, you can use a custom credentials provider to allow signing in with a username and password stored in an existing database.
_If you use a custom credentials provider user accounts will not be persisted in a database by Auth.js (even if one is configured). The option to use JSON Web Tokens for session tokens (which allow sign in without using a session database) must be enabled to use a custom credentials provider._
_If you use a custom credentials provider user accounts will not be persisted in a database by Auth.js (even if one is configured). The option to use JSON Web Tokens for session tokens (which allow sign-in without using a session database) must be enabled to use a custom credentials provider._
</p>
</details>
<details>
<summary>
<h3 style={{display:"inline-block"}}>Can I use Auth.js with a website that does not use Next.js?</h3>
<h3 style={{display: "inline-block"}}>Can I use Auth.js with a website that does not use Next.js?</h3>
</summary>
<p>
Auth.js is designed for use with Next.js and Serverless.
If you are using a different framework for your website, you can create a website that handles sign in with Next.js and then access those sessions on a website that does not use Next.js as long as the websites are on the same domain.
If you are using a different framework for your website, you can create a website that handles sign-in with Next.js and then access those sessions on a website that does not use Next.js as long as the websites are on the same domain.
If you use Auth.js on a website with a different subdomain then the rest of your website (e.g. `auth.example.com` vs `www.example.com`) you will need to set a custom cookie domain policy for the Session Token cookie. (See also: [Cookies](/reference/configuration/auth-config#cookies))
If you use Auth.js on a website with a different subdomain than the rest of your website (e.g. `auth.example.com` vs `www.example.com`) you will need to set a custom cookie domain policy for the Session Token cookie. (See also: [Cookies](/reference/configuration/auth-config#cookies))
Auth.js does not currently support automatically signing into sites on different top level domains (e.g. `www.example.com` vs `www.example.org`) using a single session.
Auth.js does not currently support automatically signing into sites on different top-level domains (e.g. `www.example.com` vs `www.example.org`) using a single session.
</p>
</details>
<details>
<summary>
<h3 style={{display:"inline-block"}}>Can I use Auth.js with React Native?</h3>
<h3 style={{display: "inline-block"}}>Can I use Auth.js with React Native?</h3>
</summary>
<p>
Auth.js is designed as a secure, confidential client and implements a server side authentication flow.
Auth.js is designed as a secure, confidential client and implements a server-side authentication flow.
It is not intended to be used in native applications on desktop or mobile applications, which typically implement public clients (e.g. with client / secrets embedded in the application).
It is not intended to be used in native applications on desktop or mobile applications, which typically implement public clients (e.g. with client/secrets embedded in the application).
</p>
</details>
<details>
<summary>
<h3 style={{display:"inline-block"}}>Is Auth.js supporting TypeScript?</h3>
<h3 style={{display: "inline-block"}}>Is Auth.js supporting TypeScript?</h3>
</summary>
<p>
@@ -103,11 +103,11 @@ Yes! Check out the [TypeScript docs](/getting-started/typescript)
<details>
<summary>
<h3 style={{display:"inline-block"}}>Is Auth.js compatible with Next.js 12 Middleware?</h3>
<h3 style={{display: "inline-block"}}>Is Auth.js compatible with Next.js 12 Middleware?</h3>
</summary>
<p>
[Next.js Middleware](https://nextjs.org/docs/middleware) is supported. Head over to the [this page](/reference/nextjs/#middleware)
[Next.js Middleware](https://nextjs.org/docs/middleware) is supported. Head over to [this page](https://next-auth.js.org/configuration/nextjs#middleware)
</p>
</details>
@@ -118,7 +118,7 @@ Yes! Check out the [TypeScript docs](/getting-started/typescript)
<details>
<summary>
<h3 style={{display:"inline-block"}}>What databases are supported by Auth.js?</h3>
<h3 style={{display: "inline-block"}}>What databases are supported by Auth.js?</h3>
</summary>
<p>
@@ -131,13 +131,13 @@ It also provides an Adapter API which allows you to connect it to any database.
<details>
<summary>
<h3 style={{display:"inline-block"}}>What does Auth.js use databases for?</h3>
<h3 style={{display: "inline-block"}}>What does Auth.js use databases for?</h3>
</summary>
<p>
Databases in Auth.js are used for persisting users, OAuth accounts, email sign in tokens and sessions.
Databases in Auth.js are used for persisting users, OAuth accounts, email sign-in tokens and sessions.
Specifying a database is optional if you don't need to persist user data or support email sign in. If you don't specify a database then JSON Web Tokens will be enabled for session storage and used to store session data.
Specifying a database is optional if you don't need to persist user data or support email sign-in. If you don't specify a database then JSON Web Tokens will be enabled for session storage and used to store session data.
If you are using a database with Auth.js, you can still explicitly enable JSON Web Tokens for sessions (instead of using database sessions).
@@ -146,24 +146,24 @@ If you are using a database with Auth.js, you can still explicitly enable JSON W
<details>
<summary>
<h3 style={{display:"inline-block"}}>Should I use a database?</h3>
<h3 style={{display: "inline-block"}}>Should I use a database?</h3>
</summary>
<p>
- Using Auth.js without a database works well for internal tools - where you need to control who is able to sign in, but when you do not need to create user accounts for them in your application.
- Using Auth.js without a database works well for internal tools - where you need to control who can sign in, but when you do not need to create user accounts for them in your application.
- Using Auth.js with a database is usually a better approach for a consumer facing application where you need to persist accounts (e.g. for billing, to contact customers, etc).
- Using Auth.js with a database is usually a better approach for a consumer-facing application where you need to persist accounts (e.g. for billing, to contact customers, etc).
</p>
</details>
<details>
<summary>
<h3 style={{display:"inline-block"}}>What database should I use?</h3>
<h3 style={{display: "inline-block"}}>What database should I use?</h3>
</summary>
<p>
Managed database solutions for MySQL, Postgres and MongoDB (and compatible databases) are well supported from cloud providers such as Amazon, Google, Microsoft and Atlas.
Managed database solutions for MySQL, Postgres and MongoDB (and compatible databases) are well supported by cloud providers such as Amazon, Google, Microsoft and Atlas.
If you are deploying directly to a particular cloud platform you may also want to consider serverless database offerings they have (e.g. [Amazon Aurora Serverless on AWS](https://aws.amazon.com/rds/aurora/serverless/)).
@@ -174,51 +174,49 @@ If you are deploying directly to a particular cloud platform you may also want t
## Security
Parts of this section has been moved to its [own page](/security).
Parts of this section have been moved to their [page](/security)](/security).
<details>
<summary>
<h3 style={{display:"inline-block"}}>How do I get Refresh Tokens and Access Tokens for an OAuth account?</h3>
<h3 style={{display: "inline-block"}}>How do I get Refresh Tokens and Access Tokens for an OAuth account?</h3>
</summary>
<p>
Auth.js provides a solution for authentication, session management and user account creation.
Auth.js records Refresh Tokens and Access Tokens on sign in (if supplied by the provider) and it will pass them, along with the User ID, Provider and Provider Account ID, to either:
Auth.js records Refresh Tokens and Access Tokens on sign-in (if supplied by the provider) and it will pass them, along with the User ID, Provider and Provider Account ID, to either:
1. A database - if a database connection string is provided
2. The JSON Web Token callback - if JWT sessions are enabled (e.g. if no database specified)
2. The JSON Web Token callback - if JWT sessions are enabled (e.g. if no database is specified)
You can then look them up from the database or persist them to the JSON Web Token.
Note: Auth.js does not currently handle Access Token rotation for OAuth providers for you, however you can check out [this tutorial](/guides/basics/refresh-token-rotation) if you want to implement it.
We also have an [example repository](https://github.com/nextauthjs/next-auth-refresh-token-example) / project based upon Auth.js v4 where we demonstrate how to use a refresh token to refresh the provided access token.
Note: Auth.js does not currently handle Access Token rotation for OAuth providers for you, however, you can check out [this tutorial](/guides/basics/refresh-token-rotation) if you want to implement it.
</p>
</details>
<details>
<summary>
<h3 style={{display:"inline-block"}}>When I sign in with another account with the same email address, why are accounts not linked automatically?</h3>
<h3 style={{display: "inline-block"}}>When I sign in with another account with the same email address, why are accounts not linked automatically?</h3>
</summary>
<p>
Automatic account linking on sign in is not secure between arbitrary providers - with the exception of allowing users to sign in via an email addresses as a fallback (as they must verify their email address as part of the flow).
Automatic account linking on sign-in is not secure between arbitrary providers - except for allowing users to sign in via email addresses as a fallback (as they must verify their email address as part of the flow).
When an email address is associated with an OAuth account it does not necessarily mean that it has been verified as belonging to account holder — how email address verification is handled is not part of the OAuth specification and varies between providers (e.g. some do not verify first, some do verify first, others return metadata indicating the verification status).
When an email address is associated with an OAuth account it does not necessarily mean that it has been verified as belonging to the account holder — how email address verification is handled is not part of the OAuth specification and varies between providers (e.g. some do not verify first, some do verify first, others return metadata indicating the verification status).
With automatic account linking on sign in, this can be exploited by bad actors to hijack accounts by creating an OAuth account associated with the email address of another user.
With automatic account linking on sign-in, this can be exploited by bad parties to hijack accounts by creating an OAuth account associated with the email address of another user.
For this reason it is not secure to automatically link accounts between arbitrary providers on sign in, which is why this feature is generally not provided by authentication service and is not provided by Auth.js.
For this reason, it is not secure to automatically link accounts between arbitrary providers on sign-in, which is why this feature is generally not provided by an authentication service and is not provided by Auth.js.
Automatic account linking is seen on some sites, sometimes insecurely. It can be technically possible to do automatic account linking securely if you trust all the providers involved to ensure they have securely verified the email address associated with the account, but requires placing trust (and transferring the risk) to those providers to handle the process securely.
Examples of scenarios where this is secure include with an OAuth provider you control (e.g. that only authorizes users internal to your organization) or with a provider you explicitly trust to have verified the users email address.
Examples of scenarios where this is secure include an OAuth provider you control (e.g. that only authorizes users internal to your organization) or a provider you explicitly trust to have verified the users' email address.
Automatic account linking is not a planned feature of Auth.js, however there is scope to improve the user experience of account linking and of handling this flow, in a secure way. Typically this involves providing a fallback option to sign in via email, which is already possible (and recommended), but the current implementation of this flow could be improved on.
Automatic account linking is not a planned feature of Auth.js, however, there is scope to improve the user experience of account linking and of handling this flow, securely. Typically this involves providing a fallback option to sign in via email, which is already possible (and recommended), but the current implementation of this flow could be improved.
Providing support for secure account linking and unlinking of additional providers - which can only be done if a user is already signed in already - was originally a feature in v1.x but has not been present since v2.0, is planned to return in a future release.
Providing support for secure account linking and unlinking of additional providers - which can only be done if a user is already signed in - was originally a feature in v1.x but has not been present since v2.0, and is planned to return in a future release.
</p>
</details>
@@ -229,11 +227,11 @@ Providing support for secure account linking and unlinking of additional provide
<details>
<summary>
<h3 style={{display:"inline-block"}}>Why doesn't Auth.js support [a particular feature]?</h3>
<h3 style={{display: "inline-block"}}>Why doesn't Auth.js support [a particular feature]?</h3>
</summary>
<p>
Auth.js is an open source project built by individual contributors who are volunteers writing code and providing support in their spare time.
Auth.js is an open-source project built by individual contributors who are volunteers writing code and providing support in their spare time.
If you would like Auth.js to support a particular feature, the best way to help make it happen is to raise a feature request describing the feature and offer to work with other contributors to develop and test it.
@@ -244,13 +242,13 @@ If you are not able to develop a feature yourself, you can offer to sponsor some
<details>
<summary>
<h3 style={{display:"inline-block"}}>I disagree with a design decision, how can I change your mind?</h3>
<h3 style={{display: "inline-block"}}>I disagree with a design decision, how can I change your mind?</h3>
</summary>
<p>
Product design decisions on Auth.js are made by core team members.
You can raise suggestions as feature requests / requests for enhancement.
You can raise suggestions as feature requests for enhancement.
Requests that provide the detail requested in the template and follow the format requested may be more likely to be supported, as additional detail prompted in the templates often provides important context.
@@ -286,7 +284,7 @@ JSON Web Tokens can be used for session tokens, but are also used for lots of ot
- JSON Web Tokens in Auth.js are secured using cryptographic encryption (JWE) to store the included information directly in a JWT session token. You may then use the token to pass information between services and APIs on the same domain without having to contact a database to verify the included information.
- You can use JWT to securely store information you do not mind the client knowing even without encryption, as the JWT is stored in a server-readable-only cookie so data in the JWT is not accessible to third party JavaScript running on your site.
- You can use JWT to securely store information you do not mind the client knowing even without encryption, as the JWT is stored in a server-readable-only cookie so data in the JWT is not accessible to third-party JavaScript running on your site.
</p>
</details>
@@ -297,15 +295,15 @@ JSON Web Tokens can be used for session tokens, but are also used for lots of ot
</summary>
<p>
- You cannot as easily expire a JSON Web Token - doing so requires maintaining a server side blocklist of invalid tokens (at least until they expire) and checking every token against the list every time a token is presented.
- It's difficult to invalidate a JSON Web Token - doing so requires maintaining a server-side blocklist of the tokens (at least until they expire) and checking every token against the list every time a token is presented.
Shorter session expiry times are used when using JSON Web Tokens as session tokens to allow sessions to be invalidated sooner and simplify this problem.
Auth.js client includes advanced features to mitigate the downsides of using shorter session expiry times on the user experience, including automatic session token rotation, optionally sending keep alive messages to prevent short lived sessions from expiring if there is an window or tab open, background re-validation, and automatic tab/window syncing that keeps sessions in sync across windows any time session state changes or a window or tab gains or loses focus.
Auth.js client includes advanced features to mitigate the downsides of using shorter session expiry times on the user experience, including automatic session token rotation, optionally sending keep-alive messages to prevent short-lived sessions from expiring if there is a window or tab opened, background re-validation, and automatic tab/window syncing that keeps sessions in sync across windows any time session state changes or a window or tab gains or loses focus.
- As with database session tokens, JSON Web Tokens are limited in the amount of data you can store in them. There is typically a limit of around 4096 bytes per cookie, though the exact limit varies between browsers, proxies and hosting services. If you want to support most browsers, then do not exceed 4096 bytes per cookie. If you want to save more data, you will need to persist your sessions in a database (Source: [browsercookielimits.iain.guru](http://browsercookielimits.iain.guru/))
The more data you try to store in a token and the more other cookies you set, the closer you will come to this limit. Since v4 we have implemented cookie chunking so that cookies over the 4kb limit get split and reassembled upon parsing. However since this data needs to be transmitted on every request, if you wish to store more than ~4 KB of data you're probably at the point where you want to store a unique ID in the token and persist the data elsewhere (e.g. in a server-side key/value store).
The more data you try to store in a token and the more other cookies you set, the closer you will come to this limit. Auth.js uses cookie chunking so that cookies over the 4kb limit get split and reassembled upon parsing. However, since this data needs to be transmitted on every request, in case you wish to store more than ~4 KB of data you're probably at the point where you want to store a unique ID in the token and persist the data elsewhere (e.g. in a server-side key/value store).
- Data stored in an encrypted JSON Web Token (JWE) may be compromised at some point.
@@ -313,7 +311,7 @@ JSON Web Tokens can be used for session tokens, but are also used for lots of ot
Avoid storing any data in a token that might be problematic if it were to be decrypted in the future.
- If you do not explicitly specify a secret for for Auth.js, existing sessions will be invalidated any time your Auth.js configuration changes, as Auth.js will default to an auto-generated secret. Since v4 this only impacts development and generating a secret is required in production.
- If you do not explicitly specify a secret for Auth.js, existing sessions will be invalidated any time your Auth.js configuration changes, as Auth.js will default to an auto-generated secret. Since v4 this only impacts development and generating a secret is required in production.
</p>
</details>
@@ -324,12 +322,10 @@ JSON Web Tokens can be used for session tokens, but are also used for lots of ot
</summary>
<p>
By default tokens are not signed (JWS) but are encrypted (JWE). Since v4 we have implemented cookie chunking so that cookies over the 4kb limit get split and reassembled upon parsing.
By default, tokens are encrypted (JWE).
You can specify other valid algorithms - [as specified in RFC 7518](https://tools.ietf.org/html/rfc7517) - with either a secret (for symmetric encryption) or a public/private key pair (for asymmetric encryption).
Auth.js will generate keys for you, but this will generate a warning at start up.
Using explicit public/private keys for signing is strongly recommended.
</p>

View File

@@ -2,6 +2,9 @@
title: Credentials authentication
---
import Tabs from "@theme/Tabs"
import TabItem from "@theme/TabItem"
Auth.js is built in a way that is flexible to integrate it with any authentication back-end you or your company may already have.
This library has been designed to handle the user session client-wise, to support multiple authentication methods (OAuth, Email, etc...) so that you're not forced to run your own authentication service.
@@ -16,34 +19,49 @@ The functionality provided for credentials based authentication is intentionally
Integrating the Credentials Provider is as simple as initializing it in the Auth.js configuration file:
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
export default NextAuth({
providers: [
CredentialsProvider({
async authorize(credentials) {
const authResponse = await fetch("/users/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(credentials),
})
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
if (!authResponse.ok) {
return null
}
export default NextAuth({
providers: [
CredentialsProvider({
async authorize(credentials) {
const authResponse = await fetch("/users/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(credentials),
})
const user = await authResponse.json()
if (!authResponse.ok) {
return null
}
return user
},
}),
],
})
```
const user = await authResponse.json()
return user
},
}),
],
})
```
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
:::note
Check the [Credentials Provider options](/reference/core/providers_credentials) for further customization

View File

@@ -7,6 +7,8 @@ import startPageImg from "./img/email-tutorial-start.png"
import checkPageImg from "./img/email-tutorial-check.png"
import mailboxImg from "./img/email-tutorial-mailbox.png"
import loggedInImg from "./img/email-tutorial-logged.png"
import Tabs from "@theme/Tabs"
import TabItem from "@theme/TabItem"
Aside from authenticating users in Auth.js via [OAuth](/getting-started/oauth-tutorial), you can also enable the option to authenticate them via "magic links". These are links that are sent to the user's email and when clicking on them they'll sign up the user automatically.
@@ -64,26 +66,43 @@ Note that we're also specifying from which domain email are going to be sent fro
Nice! We're getting there. Now we need to read supply this values as the configuration for our Email Provider. Open `pages/api/auth/[...nextauth].ts` and do the following:
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import Email from "next-auth/providers/email"
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
export default NextAuth({
providers: [
Email({
server: {
host: process.env.SMTP_HOST,
port: Number(process.env.SMTP_PORT),
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD,
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import Email from "next-auth/providers/email"
export default NextAuth({
providers: [
Email({
server: {
host: process.env.SMTP_HOST,
port: Number(process.env.SMTP_PORT),
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD,
},
},
},
from: process.env.EMAIL_FROM,
}),
],
})
```
from: process.env.EMAIL_FROM,
}),
],
})
```
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
## 3. Setting up an adapter
@@ -139,30 +158,46 @@ export default clientPromise
And now let's reference this new adapter from our Auth.js configuration file:
```diff title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import EmailProvider from "next-auth/providers/email"
+ import { MongoDBAdapter } from "@auth/mongodb-adapter"
+ import clientPromise from "../../../lib/mongodb/client"
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
```diff title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import EmailProvider from "next-auth/providers/email"
+ import { MongoDBAdapter } from "@auth/mongodb-adapter"
+ import clientPromise from "../../../lib/mongodb/client"
export default NextAuth({
secret: process.env.NEXTAUTH_SECRET,
+ adapter: MongoDBAdapter(clientPromise),
providers: [
EmailProvider({
server: {
host: process.env.EMAIL_SERVER_HOST,
port: process.env.EMAIL_SERVER_PORT,
auth: {
user: process.env.EMAIL_SERVER_USER,
pass: process.env.EMAIL_SERVER_PASSWORD
}
},
from: process.env.EMAIL_FROM
}),
],
})
```
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
export default NextAuth({
secret: process.env.NEXTAUTH_SECRET,
+ adapter: MongoDBAdapter(clientPromise),
providers: [
EmailProvider({
server: {
host: process.env.EMAIL_SERVER_HOST,
port: process.env.EMAIL_SERVER_PORT,
auth: {
user: process.env.EMAIL_SERVER_USER,
pass: process.env.EMAIL_SERVER_PASSWORD
}
},
from: process.env.EMAIL_FROM
}),
],
})
```
## 4. Wiring all together

View File

@@ -37,7 +37,7 @@ npm install next-auth
```
:::info
We are working on a new `@auth/nextjs` package that will make it easier to set up Auth.js with Next.js. Stay tuned! For now, you can use the `next-auth` package.
We are working on a new release of `next-auth` that will make it easier to set up Auth.js with Next.js. You can follow the development [on this PR](https://github.com/nextauthjs/next-auth/pull/7443)
:::
### Creating the server config
@@ -100,7 +100,7 @@ NextAuth.js provides [`useSession()`](/reference/react/#usesession) - a [React H
```ts title="pages/_app.tsx"
import { SessionProvider } from "next-auth/react"
import type { AppProps } from 'next/app'
import type { AppProps } from "next/app"
export default function App({
Component,
@@ -156,7 +156,7 @@ export default function CamperVanPage() {
### Protecting API Routes
To protect your API Routes (blocking unauthorized access to resources), you can use [`getServerSession()`](/reference/nextjs#getserversession) to know whether a session exists or not:
To protect your API Routes (blocking unauthorized access to resources), you can use [`getServerSession()`](https://next-auth.js.org/configuration/nextjs#getserversession) to know whether a session exists or not:
```ts title="pages/api/movies/list.ts"
import { getServerSession } from "next-auth/next"
@@ -182,7 +182,127 @@ export default async function listMovies(req, res) {
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO: SvelteKit
:::warning
`@auth/sveltekit` is currently experimental. The API _will_ change in the future.
:::
### Prerequisites
This tutorial assumes you have a SvelteKit application set up. If you don't, you can follow the [SvelteKit tutorial](https://kit.svelte.dev/docs/creating-a-project) to get started.
### Installing Auth.js
```bash npm2yarn
npm install @auth/core @auth/sveltekit
```
### Create server hook
Create the following [Server hook](https://kit.svelte.dev/docs/hooks) file. This route contains the necessary configuration for Auth.js, as well as the dynamic route handler:
```ts title="src/hooks.server.ts"
import { SvelteKitAuth } from "@auth/sveltekit"
import GitHub from "@auth/core/providers/github"
import { GITHUB_ID, GITHUB_SECRET } from "$env/static/private"
*
export const handle = SvelteKitAuth({
providers: [GitHub({ clientId: GITHUB_ID, clientSecret: GITHUB_SECRET })],
})
```
:::info
Behind the scenes, this creates all the relevant OAuth API routes within `/api/auth/*` so that auth API requests to:
- [GET `/api/auth/signin`](https://authjs.dev/reference/rest-api#get--apiauthsignin)
- [POST `/api/auth/signin/:provider`](https://authjs.dev/reference/rest-api#post--apiauthsigninprovider)
- [GET/POST `/api/auth/callback/:provider`](https://authjs.dev/reference/rest-api#get--post--apiauthcallbackprovider)
- [GET `/api/auth/signout`](https://authjs.dev/reference/rest-api#get--apiauthsignout)
- [POST `/api/auth/signout`](https://authjs.dev/reference/rest-api#post--apiauthsignout)
- [GET `/api/auth/session`](https://authjs.dev/reference/rest-api#get--apiauthsession)
- [GET `/api/auth/csrf`](https://authjs.dev/reference/rest-api#get--apiauthcsrf)
- [GET `/api/auth/providers`](https://authjs.dev/reference/rest-api#get--apiauthproviders)
can be handled by Auth.js. In this way, Auth.js stays in charge of the whole application's authentication request/response flow.
Auth.js is fully customizable - [our guides section](/guides/overview) teaches you how to set it up to handle auth in different ways. All the possible configuration options are [listed here](/reference/configuration/auth-config).
:::
### Adding environment variables
You may notice we are using environment variables in the code example above. We take the value of `GITHUB_ID` and `GITHUB_SECRET` from the GitHub Developer OAuth Portal. See [Configuring OAuth Provider](/getting-started/oauth-tutorial#2-configuring-oauth-provider) section on how to get those.
In your project root, create a `.env.local` file and add the `AUTH_SECRET` environment variable:
```title=".env.local"
AUTH_SECRET="This is an example"
```
`AUTH_SECRET` is a random string used by the library to encrypt tokens and email verification hashes, and **it's mandatory to keep things secure**! 🔥 🔐 . You can use:
```
$ openssl rand -base64 32
```
or https://generate-secret.vercel.app/32 to generate a random value for it.
### Exposing the session via page store
Auth.js provides us a getSession, function to access the session data and status, to call from the `event.locals` variable. We can now just call it and add it to our `$page` store.
```ts
import type { LayoutServerLoad } from './$types';
*
export const load: LayoutServerLoad = async (event) => {
return {
session: await event.locals.getSession()
};
};
```
### Consuming the session via page store
You can use the `$page.data.session` variable from anywhere on your page. Learn more about SvelteKit's page store in the [SvelteKit docs](https://learn.svelte.dev/tutorial/page-store).
```ts title="route/+page.svelte"
<script>
import { signIn, signOut } from '@auth/sveltekit/client'
import { page } from '$app/stores'
</script>
{#if $page.data.session?.user}
<p>Signed in as {$page.data.session.user.email}</p>
<button on:click={signOut}>Sign out</button>
<img src="https://cdn.pixabay.com/photo/2017/08/11/19/36/vw-2632486_1280.png" />
{:else}
<p>Not signed in.</p>
<button on:click={() => signIn('github')}>Sign in</button>
{/if}
```
### Protecting API Routes
To protect your API Routes (blocking unauthorized access to resources), you can use `locals.getSessions()` just like in the layouts file to know whether a session exists or not:
```ts title="routes/api/movies/+server.ts"
import { json, error } from "@sveltejs/kit";
import type { RequestEvent } from "./$types";
export async function GET({ locals }: RequestEvent) {
const session = await locals.getSession()
if (!session?.user) {
throw error(401, "You must sign in to view movies.");
}
return json({
movies: [
{ title: "Alien vs Predator", id: 1 },
{ title: "Reservoir Dogs", id: 2 },
]
})
}
```
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO: SolidStart
@@ -218,7 +338,7 @@ The callback URL we insert should have the following pattern:
In this case, given we want to try our authentication working locally on our machine and we're using **GitHub** as our OAuth provider, it'll be:
<Tabs groupId="frameworks">
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
```
@@ -274,7 +394,7 @@ Note that, for each provider, the configuration process will be similar to what
2. Create create your OAuth application within it
3. Set the callback URL
4. Get the Client ID and Generate a Client Secret
:::
:::
## 3. Wiring all together
@@ -289,7 +409,7 @@ GITHUB_SECRET=67890
Here is our server configuration file again:
<Tabs groupId="frameworks">
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
```ts title="pages/api/auth/[...nextauth].ts"
@@ -314,7 +434,24 @@ $ npm run next dev
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
```ts title="src/hooks.server.ts"
import { SvelteKitAuth } from "@auth/sveltekit"
import GitHub from "@auth/core/providers/github"
import { GITHUB_ID, GITHUB_SECRET } from "$env/static/private"
*
export const handle = SvelteKitAuth({
providers: [GitHub({ clientId: GITHUB_ID, clientSecret: GITHUB_SECRET })],
})
```
Great! We're now ready to run our application locally. Start the Svelte app by running on your terminal the following command and navigating to [`http://localhost:5173`](http://localhost:5173):
```
$ npm run vite dev
```
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart

View File

@@ -9,6 +9,9 @@ https://github.com/nextauthjs/next-auth-example
---
import Tabs from "@theme/Tabs"
import TabItem from "@theme/TabItem"
## Adapters
If you're writing your own custom Adapter, you can take advantage of the types to make sure your implementation conforms to what's expected:
@@ -46,30 +49,45 @@ This will work in code editors with a strong TypeScript integration like VSCode
Let's look at `Session`:
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
export default NextAuth({
callbacks: {
session({ session, token, user }) {
return session // The return type will match the one returned in `useSession()`
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
export default NextAuth({
callbacks: {
session({ session, token, user }) {
return session // The return type will match the one returned in `useSession()`
},
},
},
})
```
})
```
```ts title="pages/index.ts"
import { useSession } from "next-auth/react"
```ts title="pages/index.ts"
import { useSession } from "next-auth/react"
export default function IndexPage() {
// `session` will match the returned value of `callbacks.session()` from `NextAuth()`
const { data: session } = useSession()
export default function IndexPage() {
// `session` will match the returned value of `callbacks.session()` from `NextAuth()`
const { data: session } = useSession()
return (
// Your component
)
}
```
return (
// Your component
)
}
```
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
To extend/augment this type, create a `types/next-auth.d.ts` file in your project:

View File

@@ -8,6 +8,6 @@ An **Adapter** in Auth.js connects your application to whatever database or back
When using a database, you can still use JWT for session handling for fast access. See the [`session.strategy`](/reference/configuration/auth-config#session) option. Read about the trade-offs of JWT in the [FAQ](/concepts/faq#json-web-tokens).
:::
We have a list of official adapters that are distributed as their own packages under the `@next-auth/{name}-adapter` namespace. Their source code is available in their various adapters package directories at [`nextauthjs/next-auth`](https://github.com/nextauthjs/next-auth/tree/main/packages):
We have a list of official adapters that are distributed as their own packages under the `@auth/{name}-adapter` namespace. Their source code is available in their various adapters package directories at [`nextauthjs/next-auth`](https://github.com/nextauthjs/next-auth/tree/main/packages):
- [All available adapters](/reference/adapters)

View File

@@ -12,7 +12,7 @@ If you want to pass data such as an Access Token or User ID to the browser when
You can specify a handler for any of the callbacks below.
```js title="pages/api/auth/[...nextauth].js"s
```js title="auth.js"
callbacks: {
async signIn({ user, account, profile, email, credentials }) {
return true
@@ -35,7 +35,7 @@ The documentation below shows how to implement each callback, their default beha
Use the `signIn()` callback to control if a user is allowed to sign in.
```js title="pages/api/auth/[...nextauth].js"
```js title="auth.js"
callbacks: {
async signIn({ user, account, profile, email, credentials }) {
const isAllowedToSignIn = true
@@ -79,7 +79,7 @@ By default only URLs on the same URL as the site are allowed, you can use the re
The default redirect callback looks like this:
```js title="pages/api/auth/[...nextauth].js"
```js title="auth.js"
callbacks: {
async redirect({ url, baseUrl }) {
// Allows relative callback URLs
@@ -107,7 +107,7 @@ Requests to `/api/auth/signin`, `/api/auth/session` and calls to `getSession()`,
The contents _user_, _account_, _profile_ and _isNewUser_ will vary depending on the provider and on if you are using a database or not. You can persist data such as User ID, OAuth Access Token in this token. To make it available in the browser, check out the [`session()` callback](#session-callback) as well.
```js title="pages/api/auth/[...nextauth].js"
```js title="auth.js"
callbacks: {
async jwt({ token, account }) {
// Persist the OAuth access_token to the token right after signin
@@ -132,7 +132,7 @@ e.g. `getSession()`, `useSession()`, `/api/auth/session`
- When using database sessions, the User object is passed as an argument.
- When using JSON Web Tokens for sessions, the JWT payload is provided instead.
```js title="pages/api/auth/[...nextauth].js"
```js title="auth.js"
callbacks: {
async session({ session, token, user }) {
// Send properties to the client, like an access_token from a provider.

View File

@@ -2,6 +2,14 @@
title: Custom Initialization
---
import Tabs from "@theme/Tabs"
import TabItem from "@theme/TabItem"
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
In Next.js, you can define an API route that will catch all requests that begin with a certain path. Conveniently, this is called [Catch all API routes](https://nextjs.org/docs/api-routes/dynamic-api-routes#catch-all-api-routes).
When you define a `/pages/api/auth/[...nextauth]` JS/TS file, you instruct Auth.js that every API request beginning with `/api/auth/*` should be handled by the code written in the `[...nextauth]` file.
@@ -120,3 +128,15 @@ This way of initializing `NextAuth` is very powerful, but should be used sparing
:::warning
Changing parts of the request that is essential to `NextAuth` to do it's job - like messing with the [default cookies](/reference/configuration/auth-config#cookies) - can have unforeseen consequences, and have the potential to introduce security holes if done incorrectly. Only change those if you understand consequences.
:::
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>

View File

@@ -4,10 +4,10 @@ sidebar_label: Custom JWT encoding
---
:::warning
If you use middleware to protect routes, make sure the same method is also set in the [`_middleware.ts` options](/reference/nextjs/#custom-jwt-decode-method)
If you use middleware to protect routes, make sure the same method is also set in the [`middleware.ts` options](https://next-auth.js.org/configuration/nextjs#custom-jwt-decode-method)
:::
Auth.js uses encrypted JSON Web Tokens ([JWE](https://datatracker.ietf.org/doc/html/rfc7516)) by default. Unless you have a good reason, we recommend keeping this behaviour. Although you can override this using the `encode` and `decode` methods. Both methods must be defined at the same time.
Auth.js uses encrypted JSON Web Tokens ([JWE](https://datatracker.ietf.org/doc/html/rfc7516)) by default. Unless you have a good reason, we recommend keeping this behavior. Although you can override this using the `encode` and `decode` methods. Both methods must be defined at the same time.
```js
jwt: {

View File

@@ -2,13 +2,16 @@
title: Pages
---
import Tabs from "@theme/Tabs"
import TabItem from "@theme/TabItem"
Auth.js automatically creates simple, unbranded authentication pages for handling Sign in, Sign out, Email Verification and displaying error messages.
The options displayed on the sign-up page are automatically generated based on the providers specified in the options passed to Auth.js.
To add a custom login page, you can use the `pages` option:
```javascript title="pages/api/auth/[...nextauth].js"
```javascript title="auth.js"
...
pages: {
signIn: '/auth/signin',
@@ -76,6 +79,11 @@ In addition, you can define the background color and text color of the button wi
In order to get the available authentication providers and the URLs to use for them, you can make a request to the API endpoint `/api/auth/providers`:
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
```jsx title="pages/auth/signin.js"
import { getProviders, signIn } from "next-auth/react"
@@ -100,6 +108,18 @@ export async function getServerSideProps(context) {
}
}
```
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
There is another, more fully styled example signin page available [here](https://github.com/ndom91/next-auth-example-sign-in-page).
@@ -107,6 +127,10 @@ There is another, more fully styled example signin page available [here](https:/
If you create a custom sign in form for email sign in, you will need to submit both fields for the **email** address and **csrfToken** from **/api/auth/csrf** in a POST request to **/api/auth/signin/email**.
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
```jsx title="pages/auth/email-signin.js"
import { getCsrfToken } from "next-auth/react"
@@ -131,6 +155,18 @@ export async function getServerSideProps(context) {
}
```
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
You can also use the `signIn()` function which will handle obtaining the CSRF token for you:
```js
@@ -141,6 +177,10 @@ signIn("email", { email: "jsmith@example.com" })
If you create a sign in form for credentials based authentication, you will need to pass a **csrfToken** from **/api/auth/csrf** in a `POST` request to **/api/auth/callback/credentials**.
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
```jsx title="pages/auth/credentials-signin.js"
import { getCsrfToken } from "next-auth/react"
@@ -170,6 +210,18 @@ export async function getServerSideProps(context) {
}
```
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
You can also use the `signIn()` function which will handle obtaining the CSRF token for you:
```js

View File

@@ -2,6 +2,9 @@
title: Refresh token rotation
---
import Tabs from "@theme/Tabs"
import TabItem from "@theme/TabItem"
Refresh token rotation is the practice of updating an `access_token` on behalf of the user, without requiring interaction (eg.: re-sign in). `access_token`s are usually issued for a limited time. After they expire, the service verifying them will ignore the value. Instead of asking the user to sign in again to obtain a new `access_token`, certain providers support exchanging a `refresh_token` for a new `access_token`, renewing the expiry time. Let's see how this can be achieved.
:::note
@@ -26,6 +29,20 @@ Using the [jwt](../../reference/core/types#jwt) and [session](../../reference/co
Below is a sample implementation using Google's Identity Provider. Please note that the OAuth 2.0 request in the `refreshAccessToken()` function will vary between different providers, but the core logic should remain similar.
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js">
TODO Next.js
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)" default>
```ts
import { Auth } from "@auth/core"
import { type TokenSet } from "@auth/core/types"
@@ -109,10 +126,27 @@ declare module "@auth/core/jwt" {
}
```
</TabItem>
</Tabs>
#### Database strategy
Using the database strategy is very similar, but instead of preserving the `access_token` and `refresh_token`, we save it, well, in the database.
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js">
What
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)" default>
```ts
import { Auth } from "@auth/core"
import { type TokenSet } from "@auth/core/types"
@@ -195,6 +229,8 @@ declare module "@auth/core/jwt" {
}
}
```
</TabItem>
</Tabs>
### Client Side

View File

@@ -2,19 +2,19 @@
title: Securing Pages & API routes
---
You can easily protect client and server side rendered pages and API routes with Auth.js.
You can protect client and server-side rendered pages and API routes with Auth.js.
_You can find working examples of the approaches shown below in the [example project](https://github.com/nextauthjs/next-auth-example/)._
:::tip
The methods `getSession()` and `getToken()` both return an `object` if a session is valid and `null` if a session is invalid or has expired.
The methods `getSession()` and `getToken()` both return an `object` if a session is valid and `null` if a session is not valid or has expired.
:::
## Securing Pages
### Client Side
If data on a page is fetched using calls to secure API routes - i.e. routes which use `getSession()` or `getToken()` to access the session - you can use the `useSession` React Hook to secure pages.
If data on a page is fetched using calls to secure API routes - i.e. routes that use `getSession(`)` or `getToken()` to access the session - you can use the `useSession` React Hook to secure pages.
```js title="pages/client-side-example.js"
import { useSession, getSession } from "next-auth/react"
@@ -41,7 +41,7 @@ export default function Page() {
### Next.js (Middleware)
With Auth.js 4.2.0 and Next.js 12, you can now protect your pages via the middleware pattern more easily. If you would like to protect all pages, you can create a `_middleware.js` file in your root `pages` directory which looks like this.
With NextAuth.js 4.2.0 and Next.js 12, you can now protect your pages via the middleware pattern more easily. If you would like to protect all pages, you can create a `_middleware.js` file in your root `pages` directory which looks like this.
```js title="/middleware.js"
export { default } from "next-auth/middleware"
@@ -49,15 +49,15 @@ export { default } from "next-auth/middleware"
Otherwise, if you only want to protect a subset of pages, you could put it in a subdirectory as well, for example in `/pages/admin/_middleware.js` would protect all pages under `/admin`.
For the time being, the `withAuth` middleware only supports `"jwt"` as [session strategy](/reference/configuration/auth-config#session).
For the time being, the `withAuth` middleware only supports `"jwt"` as a [session strategy](/reference/configuration/auth-config#session).
More details can be found [here](/reference/nextjs/#middleware).
More details can be found [here](https://next-auth.js.org/configuration/nextjs#middleware).
### Server Side
You can protect server side rendered pages using the `unstable_getServerSession` method. This is different from the old `getSession()` method, in that it does not do an extra fetch out over the internet to confirm data from itself, increasing performance significantly.
You can protect server-side rendered pages using the `unstable_getServerSession` method. This is different from the old `getSession()` method, in that it does not do an extra fetch out over the internet to confirm data from itself, increasing performance significantly.
You need to add this to every server rendered page you want to protect. Be aware, `unstable_getServerSession` takes slightly different arguments than the method it is replacing, `getSession`.
You need to add this to every server-rendered page you want to protect. Be aware, `unstable_getServerSession` takes slightly different arguments than the method it is replacing, `getSession`.
```js title="pages/server-side-example.js"
import { unstable_getServerSession } from "next-auth/next"
@@ -136,7 +136,7 @@ export default async (req, res) => {
### Using getToken()
If you are using JSON Web Tokens you can use the `getToken()` helper to access the contents of the JWT without having to handle JWT decryption / verification yourself. This method can only be used server side.
If you are using JSON Web Tokens you can use the `getToken()` helper to access the contents of the JWT without having to handle JWT decryption/verification yourself. This method can only be used server side.
```js title="pages/api/get-token-example.js"
// This is an example of how to read a JSON Web Token from an API route
@@ -157,7 +157,7 @@ export default async (req, res) => {
```
:::tip
You can use the `getToken()` helper function in any application as long as you set the `NEXTAUTH_URL` environment variable and the application is able to read the JWT cookie (e.g. is on the same domain).
You can use the `getToken()` helper function in any application as long as you set the `NEXTAUTH_URL` environment variable and the application can read the JWT cookie (e.g. is on the same domain).
:::
:::note

View File

@@ -22,7 +22,7 @@ This can be done by simply returning a `200` response on `HEAD` requests at the
For example
```jsx title="/pages/api/auth/[...nextauth].js"
```jsx title="auth.js"
import type { NextApiRequest, NextApiResponse } from "next"
import NextAuth from "next-auth"

View File

@@ -24,7 +24,7 @@ index 77161bd..1082fba 100644
var _openidClient = require("openid-client");
+var HttpsProxyAgent = require("https-proxy-agent");
+import { HttpsProxyAgent } from 'https-proxy-agent';
+
async function openidClient(options) {
const provider = options.provider;

View File

@@ -7,11 +7,7 @@ The Credentials provider allows you to handle signing in with arbitrary credenti
It is intended to support use cases where you have an existing system you need to authenticate users against.
It comes with the constraint that users authenticated in this manner are not persisted in the database, and consequently that the Credentials provider can only be used if JSON Web Tokens are enabled for sessions.
:::warning
The functionality provided for credentials-based authentication is intentionally limited to discourage the use of passwords due to the inherent security risks associated with them and the additional complexity associated with supporting usernames and passwords.
:::
It comes with the constraint that users authenticated in this manner are not persisted in the database by default, and consequently, that the Credentials provider can only be used if JSON Web Tokens are enabled for sessions.
## Options
@@ -23,19 +19,33 @@ You can override any of the options to suit your own use case.
## Example - Username / Password
The Credentials provider is specified like other providers, except that you need to define a handler for `authorize()` that accepts credentials submitted via HTTP POST as input and returns either:
:::caution
The functionality provided for credentials-based authentication is intentionally limited to discourage the use of passwords due to the inherent security risks of the username-password model.
1. A `user` object, which indicates the credentials are valid.
OAuth providers spend significant amounts of money, time, and engineering effort to build:
If you return an object it will be persisted to the JSON Web Token and the user will be signed in, unless a custom `signIn()` callback is configured that subsequently rejects it.
- bot-protection
- rate-limiting
- password management
- data security
2. If you return `null` then an error will be displayed advising the user to check their details.
and much more for authentication solutions. It is likely that your application would benefit from leveraging these battle-tested solutions rather than try to rebuild them from scratch.
3. If you throw an Error, the user will be sent to the error page with the error message as a query parameter.
If you'd still like to build password-based authentication for your application despite these risks, Auth.js gives you full control to do so.
The Credentials provider's `authorize()` method also provides the request object as the second parameter (see the example below).
:::
```js title="pages/api/auth/[...nextauth].js"
The Credentials provider is specified like other providers, except that you need to define a handler for `authorize()` that accepts credentials submitted via HTTP POST as input and returns a `user` object, which indicates the credentials are valid.
If you return an object it will be persisted to the JSON Web Token and the user will be signed in (unless a custom `signIn()` callback is configured that subsequently rejects it).
- If you return `null` then an error will be displayed advising the user to check their details.
- If you throw an Error, the user will be sent to the error page with the error message as a query parameter.
The Credentials provider's `authorize()` method also provides the request object as the second parameter. Here's an example that handles these concerns.
```js title="auth.js"
import CredentialsProvider from "next-auth/providers/credentials";
...
providers: [
@@ -69,7 +79,50 @@ providers: [
...
```
See the [callbacks documentation](/reference/configuration/auth-config#callbacks) for more information on how to interact with the token.
See the [callbacks documentation](/reference/configuration/auth-config#callbacks) for more information on how to interact with the token. For example, you can add additional information to the token by returning an object from the `jwt()` callback:
```js
callbacks: {
async jwt(token, user, account, profile, isNewUser) {
if (user) {
token.id = user.id
}
return token
}
}
```
### Using a database
You can also use the `authorize()` callback to interact with your database to regain some of the functionality from [more powerful providers](reference/core/providers):
```js
...
providers: [
CredentialsProvider({
...
async authorize(credentials, req) {
let user = null
const saltedPasswordToCheck = passwordToSalt(credentials.password)
user = await getUserFromDb(credentials.username, credentials.password)
if (!user) {
const saltedPassword = passwordToSalt(credentials.password)
user = await addUserToDb(credentials.username, saltedPassword)
}
if (!user) {
throw new Error("User was not found and could not be created.")
}
return user
}
})
]
...
```
## Example - Web3 / Signin With Ethereum
@@ -78,8 +131,8 @@ The credentials provider can also be used to integrate with a service like [Sign
For more information, check out the links below:
- [Tutorial](https://docs.login.xyz/integrations/Auth.js)
- [Example App Repo](https://github.com/spruceid/siwe-next-auth-example).
- [Example App Demo](https://siwe-next-auth-example2.vercel.app/).
- [Example App Repo](https://github.com/spruceid/siwe-next-auth-example)
- [Example App Demo](https://siwe-next-auth-example2.vercel.app/)
## Multiple providers

View File

@@ -17,15 +17,15 @@ We will also refer to the [Prisma Adapter](/reference/adapter/prisma). A [databa
## Setup
First, if you do not have a project using Auth.js, clone and set up a basic Auth.js project like the one [provided in](https://github.com/nextauthjs/next-auth-example.git) our example repo](https://github.com/nextauthjs/next-auth-example.git).
First, if you do not have a project using Auth.js, clone and set up a basic Auth.js project like the one [provided in our example repo](https://github.com/nextauthjs/next-auth-example).
- Install the [Prisma Adapter](/reference/adapter/prisma)
- Generate an API key from your cloud Email provider of choice and add it to your `.env.*` file. For example, mine is going to be called `SENDGRID_API`
- Add the following configuration to your configuration file:
```js title="pages/api/auth/[...nextauth].ts"
```js title="auth.ts"
import NextAuth, { NextAuthOptions } from "next-auth"
import { PrismaAdapter } from "@next-auth/prisma-adapter"
import { PrismaAdapter } from "@auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"
const prisma = new PrismaClient()
@@ -42,16 +42,15 @@ export const authOptions: NextAuthOptions = {
],
}
export default NextAuth(authOptions)
```
Next, all that's left to do is call the HTTP endpoint from our cloud email provider and pass it the required metadata like the `to` address, the email `body`, and any other fields we may need to include.
As mentioned earlier, we're going to be using SendGrid in this example, so the appropriate endpoint is `https://api.sendgrid.com/v3/mail/send` ([more info](https://docs.sendgrid.com/for-developers/sending-email/api-getting-started)). Therefore, we're going to pull out some of the important information from the `params` argument and use it in a `fetch()` call to the previously mentioned SendGrid API.
```js title="pages/api/auth/[...nextauth].ts"
```js title="auth.ts"
import NextAuth, { NextAuthOptions } from "next-auth"
import { PrismaAdapter } from "@next-auth/prisma-adapter"
import { PrismaAdapter } from "@auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"
const prisma = new PrismaClient()

View File

@@ -46,7 +46,7 @@ Create an `.env` file to the root of your project and add the connection string
Now you can add the email provider like this:
```js {3} title="pages/api/auth/[...nextauth].js"
```js {3} title="auth.js"
import EmailProvider from "next-auth/providers/email";
...
providers: [
@@ -71,7 +71,7 @@ EMAIL_FROM=noreply@example.com
Now you can add the provider settings to the NextAuth options object in the Email Provider.
```js title="pages/api/auth/[...nextauth].js"
```js title="auth.js"
import EmailProvider from "next-auth/providers/email";
...
providers: [
@@ -101,7 +101,7 @@ You can fully customize the sign in email that is sent by passing a custom funct
e.g.
```js {3} title="pages/api/auth/[...nextauth].js"
```js {3} title="auth.js"
import EmailProvider from "next-auth/providers/email";
...
providers: [
@@ -206,7 +206,7 @@ If you want to generate great looking email client compatible HTML with React, c
By default, we are generating a random verification token. You can define a `generateVerificationToken` method in your provider options if you want to override it:
```js title="pages/api/auth/[...nextauth].js"
```js title="auth.js"
providers: [
EmailProvider({
async generateVerificationToken() {

View File

@@ -5,6 +5,10 @@ title: Overview
Using an Auth.js / NextAuth.js adapter you can connect to any database service or even several different services at the same time. The following listed official adapters are created and maintained by the community:
<div class="adapter-card-list">
<a href="/reference/adapter/edgedb" class="adapter-card">
<img src="/img/adapters/edgedb.svg" width="30" />
<h4 class="adapter-card__title">EdgeDB Adapter</h4>
</a>
<a href="/reference/adapter/dgraph" class="adapter-card">
<img src="/img/adapters/dgraph.png" width="30" />
<h4 class="adapter-card__title">Dgraph Adapter</h4>

View File

@@ -4,29 +4,30 @@ title: Overview
This section of the documentation contains the API reference for all the official packages under the `@auth/*` and `@next-auth/*` scopes.
:::warning Warning
The API reference is being migrated from the [old documentation page](https://next-auth.js.org), so there are going to be references to `next-auth` still. We are continuously working on updating the naming/references.
:::
## Roadmap
Here are the _currently_ planned and released packages under the `@auth/*` scope. This is not an exhaustive list, but the set of packages that we would like to focus on to begin with.
Here are the _state_ of planned and released packages under the `@auth/*` scope. This is not an exhaustive list, but the set of packages that we would like to focus on, to begin with.
| Feature | Status |
| ------------------- | -------- |
| `@auth/nextjs` | Planned |
| `@auth/*-adapter` | Planned |
| `@auth/core` | Experimental |
| `@auth/sveltekit` | Experimental |
| `@auth/solid-start` | Experimental |
| Feature | Status |
| ---------------------- | -------- |
| `@auth/*-adapter` | Released (stable). Fully compatible with `next-auth` and all `@auth/*` libraries. |
| `@next-auth/*-adapter` | Maintenance has stopped. Update to `@auth/*-adapter`. See above. |
| `@auth/core` | Released (experimental). |
| `@auth/sveltekit` | Released (experimental, [help needed](#help-needed)). |
| `@auth/solid-start` | Released (experimental, [help needed](#help-needed)). Community package: [`@solid-mediakit/auth`](https://www.npmjs.com/package/@solid-mediakit/auth) |
| `@auth/express` | [Planned](https://github.com/nextauthjs/next-auth/issues/8257). |
| `@auth/remix` | Planned, [help needed](#help-needed). |
| `@auth/astro` | Planned, [help needed](#help-needed). |
| `@auth/nuxt` | Planned, [help needed](#help-needed). Community packages: [`@sidebase/nuxt-auth`](https://github.com/sidebase/nuxt-auth), [`@hebilicious/authjs-nuxt`](https://authjs-nuxt.pages.dev/) |
### Community Packages
While we are migrating the documentation and working on stabilizing the core package, the community has been working on some packages that are already available. With collaboration, we hope to make these packages official in the future.
:::note
If you are a maintainer of a package, [reach out](https://twitter.com/balazsorban44) if you want to collaborate on making it official or open a PR to add it to the list below, so others can discover it more easily.
:::info
`next-auth` is still the official package for Next.js. The documentation is at [next-auth.js.org](https://next-auth.js.org), while guides are being migrated over to the new documentation page. A major refactor of `next-auth` is on the way, you can [follow this PR](https://github.com/nextauthjs/next-auth/pull/7443) for updates.
:::
- ...
- ...
### Help needed
In case you are a maintainer of a package that uses `@auth/core`, feel free to [reach out to Balázs](https://twitter.com/balazsorban44), if you want to collaborate on making it an official package, maintained in our repository. If you are interested in bringing `@auth/core` support to your favorite framework, we would love to hear from you!
#### Community Packages
While we are migrating the documentation and working on stabilizing the core package, the community has been working on some packages that are already available. With collaboration, we hope to make these packages official in the future.

View File

@@ -1,7 +0,0 @@
---
title: Client
---
:::warning WIP
`@auth/nextjs/client` is work in progress. For now, please use [NextAuth.js Client API](https://next-auth.js.org/getting-started/client).
:::

View File

@@ -1,7 +0,0 @@
---
title: Next.js Auth
---
:::warning WIP
`@auth/nextjs` is work in progress. For now, please use [NextAuth.js](https://next-auth.js.org).
:::

View File

@@ -213,7 +213,25 @@ const docusaurusConfig = {
breadcrumbs: false,
routeBasePath: "/",
sidebarPath: require.resolve("./sidebars.js"),
editUrl: "https://github.com/nextauthjs/next-auth/edit/main/docs",
/**
*
* @param {{
* version: string;
* versionDocsDirPath: string;
* docPath: string;
* permalink: string;
* locale: string;
*}} params
*/
editUrl({ docPath }) {
// TODO: support other packages, fix directory links like "providers"
if (docPath.includes("reference/core")) {
const file = docPath.split("reference/core/")[1].replace(".md", ".ts").replace("_", "/")
const base = `https://github.com/nextauthjs/next-auth/edit/main/packages/core/src/${file}`
return base
}
return "https://github.com/nextauthjs/next-auth/edit/main/docs"
},
lastVersion: "current",
showLastUpdateAuthor: true,
showLastUpdateTime: true,
@@ -264,6 +282,7 @@ const docusaurusConfig = {
...(process.env.TYPEDOC_SKIP_ADAPTERS
? []
: [
typedocAdapter("EdgeDb"),
typedocAdapter("Dgraph"),
typedocAdapter("Drizzle"),
typedocAdapter("DynamoDB"),

View File

@@ -27,15 +27,15 @@
"styled-components": "5.3.6"
},
"devDependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/eslint-plugin": "2.3.1",
"@docusaurus/module-type-aliases": "2.3.1",
"@docusaurus/preset-classic": "2.3.1",
"@docusaurus/theme-common": "2.3.1",
"@docusaurus/theme-mermaid": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/core": "2.4.1",
"@docusaurus/eslint-plugin": "2.4.1",
"@docusaurus/module-type-aliases": "2.4.1",
"@docusaurus/preset-classic": "2.4.1",
"@docusaurus/theme-common": "2.4.1",
"@docusaurus/theme-mermaid": "2.4.1",
"@docusaurus/types": "2.4.1",
"docusaurus-plugin-typedoc": "1.0.0-next.5",
"typedoc": "^0.24.4",
"typedoc": "^0.24.8",
"typedoc-plugin-markdown": "4.0.0-next.6"
},
"browserslist": {

View File

@@ -34,17 +34,9 @@ module.exports = {
items: [{ type: "autogenerated", dirName: "reference/solidstart" }],
},
{
type: "category",
label: "@auth/nextjs",
link: { type: "doc", id: "reference/nextjs/index" },
items: [
"reference/nextjs/client",
{
type: "link",
label: "NextAuth.js (next-auth)",
href: "https://next-auth.js.org",
},
],
type: "link",
label: "NextAuth.js (next-auth)",
href: "https://next-auth.js.org",
},
...(process.env.TYPEDOC_SKIP_ADAPTERS
? []

4
docs/static/img/adapters/edgedb.svg vendored Normal file
View File

@@ -0,0 +1,4 @@
<svg style="color:#1F8AED" width="140" height="114" viewBox="0 0 140 114" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M118.58 56.966C118.58 66.6274 114.706 68.3592 110.377 68.3592H101.171V45.5728H110.377C114.706 45.5728 118.58 47.3046 118.58 56.966ZM113.887 56.966C113.887 50.2212 111.836 49.9022 108.874 49.9022H106.003V64.0298H108.874C111.836 64.0298 113.887 63.7108 113.887 56.966ZM65.1234 68.3592V45.5728H79.6155V49.9022H69.9541V54.5507H77.2458V58.8345H69.9541V64.0298H79.6155V68.3592H65.1234ZM87.7282 113.932H92.5589V0H87.7282V113.932ZM128.242 58.242V64.0298H132.252C134.758 64.0298 135.396 62.3892 135.396 61.1587C135.396 60.2017 134.941 58.242 131.523 58.242H128.242ZM128.242 49.9022V54.2317H131.523C133.391 54.2317 134.485 53.4113 134.485 52.0442C134.485 50.677 133.391 49.9022 131.523 49.9022H128.242ZM123.411 45.5728H132.708C137.585 45.5728 139.043 48.9908 139.043 51.4517C139.043 53.7304 137.585 55.371 136.582 55.8267C139.499 57.2395 140 60.1105 140 61.5689C140 63.4829 139.043 68.3592 132.708 68.3592H123.411V45.5728ZM37.3702 56.966C37.3702 66.6274 33.4966 68.3592 29.1671 68.3592H19.9614V45.5728H29.1671C33.4966 45.5728 37.3702 47.3046 37.3702 56.966ZM51.5885 64.2121C54.0495 64.2121 55.3255 63.3918 55.7812 62.8449V60.3384H51.862V56.4191H59.6549V65.4881C58.9713 66.5363 55.2344 68.5871 51.8164 68.5871C46.211 68.5871 41.4714 66.3996 41.4714 56.7381C41.4714 47.0767 46.2565 45.345 50.5859 45.345C57.3763 45.345 59.0625 48.8996 59.6094 52.0442L55.5989 52.9556C55.3711 51.4973 54.095 49.6744 51.1784 49.6744C48.2162 49.6744 46.1654 49.9934 46.1654 56.7381C46.1654 63.4829 48.3073 64.2121 51.5885 64.2121ZM32.6756 56.966C32.6756 50.2212 30.6248 49.9022 27.6626 49.9022H24.7915V64.0298H27.6626C30.6248 64.0298 32.6756 63.7108 32.6756 56.966ZM0 68.3592V45.5728H14.4921V49.9022H4.83072V54.5507H12.1224V58.8345H4.83072V64.0298H14.4921V68.3592H0Z" fill="currentColor">
</path>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

27
docs/static/img/providers/click-up.svg vendored Normal file
View File

@@ -0,0 +1,27 @@
<svg width="185" height="185" viewBox="0 0 185 185" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d)">
<rect x="30" y="20" width="125" height="125" rx="62.5" fill="white"/>
<rect x="30" y="20" width="125" height="125" rx="62.5" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M55.8789 105.714L69.3974 95.3593C76.5762 104.732 84.1998 109.051 92.6948 109.051C101.143 109.051 108.557 104.781 115.414 95.4832L129.119 105.59C119.232 118.996 106.932 126.079 92.6948 126.079C78.5049 126.079 66.0907 119.046 55.8789 105.714Z" fill="url(#paint0_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M92.6491 60.7078L68.5883 81.4406L57.4727 68.5407L92.6969 38.1885L127.647 68.5644L116.477 81.417L92.6491 60.7078Z" fill="url(#paint1_linear)"/>
</g>
<defs>
<filter id="filter0_d" x="0" y="0" width="185" height="185" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="10"/>
<feGaussianBlur stdDeviation="15"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.117647 0 0 0 0 0.211765 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<linearGradient id="paint0_linear" x1="55.8789" y1="116.251" x2="129.119" y2="116.251" gradientUnits="userSpaceOnUse">
<stop stop-color="#8930FD"/>
<stop offset="1" stop-color="#49CCF9"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="57.4727" y1="67.6025" x2="127.647" y2="67.6025" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF02F0"/>
<stop offset="1" stop-color="#FFC800"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 0C7.16704 0 0 7.16704 0 16C0 24.833 7.16704 32 16 32C24.8156 32 32 24.833 32 16C32 7.16704 24.8156 0 16 0ZM26.5683 7.37526C28.4772 9.70064 29.6226 12.6681 29.6573 15.8785C29.2061 15.7917 24.6941 14.872 20.1475 15.4447C20.0434 15.2191 19.9566 14.9761 19.8525 14.7332C19.5748 14.0738 19.2625 13.397 18.9501 12.7549C23.9827 10.7072 26.2733 7.75706 26.5683 7.37526ZM16 2.36009C19.4707 2.36009 22.6464 3.6616 25.0586 5.7961C24.8156 6.14317 22.7505 8.9024 17.8916 10.7245C15.6529 6.61171 13.1714 3.24512 12.7896 2.72451C13.8134 2.48156 14.8894 2.36009 16 2.36009ZM10.1866 3.64426C10.551 4.13014 12.9805 7.51411 15.2538 11.5401C8.86768 13.2408 3.22778 13.2061 2.62039 13.2061C3.50541 8.97181 6.36877 5.44902 10.1866 3.64426ZM2.32538 16.0173C2.32538 15.8785 2.32538 15.7397 2.32538 15.6009C2.9154 15.6182 9.54448 15.705 16.3644 13.6573C16.7636 14.4208 17.128 15.2017 17.475 15.9827C17.3015 16.0347 17.1106 16.0868 16.9371 16.1388C9.89155 18.4122 6.14317 24.6247 5.83082 25.1453C3.6616 22.7332 2.32538 19.5228 2.32538 16.0173ZM16 29.6746C12.8417 29.6746 9.92624 28.5987 7.61821 26.7939C7.86118 26.2907 10.6378 20.9458 18.3427 18.256C18.3774 18.2386 18.3948 18.2386 18.4295 18.2212C20.3557 23.2017 21.1367 27.3839 21.3449 28.5813C19.6963 29.2928 17.8916 29.6746 16 29.6746ZM23.6182 27.3319C23.4794 26.4989 22.7506 22.5076 20.9631 17.5965C25.2495 16.9197 28.9978 18.0304 29.4664 18.1866C28.8764 21.987 26.6898 25.2668 23.6182 27.3319Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 0C7.16704 0 0 7.16704 0 16C0 24.833 7.16704 32 16 32C24.8156 32 32 24.833 32 16C32 7.16704 24.8156 0 16 0ZM26.5683 7.37526C28.4772 9.70064 29.6226 12.6681 29.6573 15.8785C29.2061 15.7917 24.6941 14.872 20.1475 15.4447C20.0434 15.2191 19.9566 14.9761 19.8525 14.7332C19.5748 14.0738 19.2625 13.397 18.9501 12.7549C23.9827 10.7072 26.2733 7.75706 26.5683 7.37526ZM16 2.36009C19.4707 2.36009 22.6464 3.6616 25.0586 5.7961C24.8156 6.14317 22.7505 8.9024 17.8916 10.7245C15.6529 6.61171 13.1714 3.24512 12.7896 2.72451C13.8134 2.48156 14.8894 2.36009 16 2.36009ZM10.1866 3.64426C10.551 4.13014 12.9805 7.51411 15.2538 11.5401C8.86768 13.2408 3.22778 13.2061 2.62039 13.2061C3.50541 8.97181 6.36877 5.44902 10.1866 3.64426ZM2.32538 16.0173C2.32538 15.8785 2.32538 15.7397 2.32538 15.6009C2.9154 15.6182 9.54448 15.705 16.3644 13.6573C16.7636 14.4208 17.128 15.2017 17.475 15.9827C17.3015 16.0347 17.1106 16.0868 16.9371 16.1388C9.89155 18.4122 6.14317 24.6247 5.83082 25.1453C3.6616 22.7332 2.32538 19.5228 2.32538 16.0173ZM16 29.6746C12.8417 29.6746 9.92624 28.5987 7.61821 26.7939C7.86118 26.2907 10.6378 20.9458 18.3427 18.256C18.3774 18.2386 18.3948 18.2386 18.4295 18.2212C20.3557 23.2017 21.1367 27.3839 21.3449 28.5813C19.6963 29.2928 17.8916 29.6746 16 29.6746ZM23.6182 27.3319C23.4794 26.4989 22.7506 22.5076 20.9631 17.5965C25.2495 16.9197 28.9978 18.0304 29.4664 18.1866C28.8764 21.987 26.6898 25.2668 23.6182 27.3319Z" fill="#EA4C89"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

10
docs/static/img/providers/mastodon.svg vendored Normal file
View File

@@ -0,0 +1,10 @@
<svg width="75" height="79" viewBox="0 0 75 79" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M73.8393 17.4898C72.6973 9.00165 65.2994 2.31235 56.5296 1.01614C55.05 0.797115 49.4441 0 36.4582 0H36.3612C23.3717 0 20.585 0.797115 19.1054 1.01614C10.5798 2.27644 2.79399 8.28712 0.904997 16.8758C-0.00358524 21.1056 -0.100549 25.7949 0.0682394 30.0965C0.308852 36.2651 0.355538 42.423 0.91577 48.5665C1.30307 52.6474 1.97872 56.6957 2.93763 60.6812C4.73325 68.042 12.0019 74.1676 19.1233 76.6666C26.7478 79.2728 34.9474 79.7055 42.8039 77.9162C43.6682 77.7151 44.5217 77.4817 45.3645 77.216C47.275 76.6092 49.5123 75.9305 51.1571 74.7385C51.1797 74.7217 51.1982 74.7001 51.2112 74.6753C51.2243 74.6504 51.2316 74.6229 51.2325 74.5948V68.6416C51.2321 68.6154 51.2259 68.5896 51.2142 68.5661C51.2025 68.5426 51.1858 68.522 51.1651 68.5058C51.1444 68.4896 51.1204 68.4783 51.0948 68.4726C51.0692 68.4669 51.0426 68.467 51.0171 68.4729C45.9835 69.675 40.8254 70.2777 35.6502 70.2682C26.7439 70.2682 24.3486 66.042 23.6626 64.2826C23.1113 62.762 22.7612 61.1759 22.6212 59.5646C22.6197 59.5375 22.6247 59.5105 22.6357 59.4857C22.6466 59.4609 22.6633 59.4391 22.6843 59.422C22.7053 59.4048 22.73 59.3929 22.7565 59.3871C22.783 59.3813 22.8104 59.3818 22.8367 59.3886C27.7864 60.5826 32.8604 61.1853 37.9522 61.1839C39.1768 61.1839 40.3978 61.1839 41.6224 61.1516C46.7435 61.008 52.1411 60.7459 57.1796 59.7621C57.3053 59.7369 57.431 59.7154 57.5387 59.6831C65.4861 58.157 73.0493 53.3672 73.8178 41.2381C73.8465 40.7606 73.9184 36.2364 73.9184 35.7409C73.9219 34.0569 74.4606 23.7949 73.8393 17.4898Z" fill="url(#paint0_linear_549_34)"/>
<path d="M61.2484 27.0263V48.114H52.8916V27.6475C52.8916 23.3388 51.096 21.1413 47.4437 21.1413C43.4287 21.1413 41.4177 23.7409 41.4177 28.8755V40.0782H33.1111V28.8755C33.1111 23.7409 31.0965 21.1413 27.0815 21.1413C23.4507 21.1413 21.6371 23.3388 21.6371 27.6475V48.114H13.2839V27.0263C13.2839 22.7176 14.384 19.2946 16.5843 16.7572C18.8539 14.2258 21.8311 12.926 25.5264 12.926C29.8036 12.926 33.0357 14.5705 35.1905 17.8559L37.2698 21.346L39.3527 17.8559C41.5074 14.5705 44.7395 12.926 49.0095 12.926C52.7013 12.926 55.6784 14.2258 57.9553 16.7572C60.1531 19.2922 61.2508 22.7152 61.2484 27.0263Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_549_34" x1="37.0692" y1="0" x2="37.0692" y2="79" gradientUnits="userSpaceOnUse">
<stop stop-color="#6364FF"/>
<stop offset="1" stop-color="#563ACC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg fill="#ffffff" width="64px" height="64px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" stroke="#ffffff">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>

After

Width:  |  Height:  |  Size: 1.6 KiB

14
docs/static/img/providers/tiktok.svg vendored Normal file
View File

@@ -0,0 +1,14 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-label="TikTok" role="img" viewBox="0 0 512.00 512.00" width="64px" height="64px" fill="#000000" stroke="#000000" stroke-width="0.00512">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" stroke="#CCCCCC" stroke-width="1.024"/>
<g id="SVGRepo_iconCarrier">
<rect rx="15%" height="512" width="512" fill="#ffffff"/>
<defs>

After

Width:  |  Height:  |  Size: 924 B

View File

@@ -6,7 +6,7 @@
"scripts": {
"build:app": "turbo run build --filter=next-auth-app",
"build:docs": "turbo run build --filter=docs",
"build": "turbo run build --filter=next-auth --filter=@next-auth/* --filter=@auth/* --no-deps",
"build": "turbo run build --filter=next-auth --filter=@auth/* --no-deps",
"test": "turbo run test --concurrency=1 --filter=[HEAD^1] --filter=./packages/* --filter=!@*upstash* --filter=!*dynamodb-* --filter=!*app*",
"clean": "turbo run clean --no-cache",
"dev:db": "turbo run dev --parallel --continue --filter=next-auth-app...",
@@ -43,13 +43,13 @@
"eslint-plugin-svelte3": "^4.0.0",
"prettier": "2.8.1",
"prettier-plugin-svelte": "^2.8.1",
"turbo": "^1.10.3",
"typescript": "4.9.4"
"turbo": "^1.10.12",
"typescript": "5.2.2"
},
"engines": {
"node": "^16.13.0 || ^18.12.0"
},
"packageManager": "pnpm@7.23.0",
"packageManager": "pnpm@8.7.1",
"funding": [
{
"type": "github",
@@ -249,6 +249,7 @@
{
"files": [
"apps/dev/nextjs/pages/api/auth/[...nextauth].ts",
"apps/examples/nextjs/auth.ts",
"docs/{sidebars,docusaurus.config}.js"
],
"options": {

View File

@@ -41,13 +41,13 @@
"test": "./tests/test.sh"
},
"devDependencies": {
"@next-auth/adapter-test": "workspace:*",
"@next-auth/tsconfig": "workspace:*",
"@auth/adapter-test": "workspace:*",
"@auth/tsconfig": "workspace:*",
"@types/jest": "^26.0.24",
"@types/jsonwebtoken": "^8.5.5",
"@types/node-fetch": "^2.5.11",
"jest": "^27.4.3",
"ts-jest": "^27.0.3",
"typescript": "5.2.2",
"undici": "5.22.1"
},
"dependencies": {
@@ -55,6 +55,6 @@
"jsonwebtoken": "^8.5.1"
},
"jest": {
"preset": "@next-auth/adapter-test/jest"
"preset": "@auth/adapter-test/jest"
}
}
}

View File

@@ -1,7 +1,7 @@
import { DgraphAdapter, format } from "../src"
import { client as dgraphClient } from "../src/lib/client"
import * as fragments from "../src/lib/graphql/fragments"
import { runBasicTests } from "@next-auth/adapter-test"
import { runBasicTests } from "@auth/adapter-test"
import fs from "fs"
import path from "path"

View File

@@ -1,5 +1,5 @@
{
"extends": "@next-auth/tsconfig/tsconfig.base.json",
"extends": "@auth/tsconfig/tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",

View File

@@ -1,6 +1,6 @@
{
"name": "@auth/drizzle-adapter",
"version": "0.3.0",
"version": "0.3.2",
"description": "Drizzle adapter for Auth.js.",
"homepage": "https://authjs.dev",
"repository": "https://github.com/nextauthjs/next-auth",
@@ -11,8 +11,8 @@
"type": "module",
"types": "./index.d.ts",
"files": [
"*.js",
"*.d.ts*",
"*.js",
"lib",
"src"
],
@@ -48,8 +48,8 @@
"@auth/core": "workspace:*"
},
"devDependencies": {
"@next-auth/adapter-test": "workspace:*",
"@next-auth/tsconfig": "workspace:*",
"@auth/adapter-test": "workspace:*",
"@auth/tsconfig": "workspace:*",
"@types/better-sqlite3": "^7.6.4",
"@types/uuid": "^8.3.3",
"better-sqlite3": "^8.4.0",
@@ -60,6 +60,6 @@
"postgres": "^3.3.4"
},
"jest": {
"preset": "@next-auth/adapter-test/jest"
"preset": "@auth/adapter-test/jest"
}
}
}

View File

@@ -16,19 +16,14 @@
* @module @auth/drizzle-adapter
*/
import { MySqlTableFn } from "drizzle-orm/mysql-core/index.js"
import { PgTableFn } from "drizzle-orm/pg-core/index.js"
import { SQLiteTableFn } from "drizzle-orm/sqlite-core/index.js"
import { MySqlDatabase, MySqlTableFn } from "drizzle-orm/mysql-core"
import { PgDatabase, PgTableFn } from "drizzle-orm/pg-core"
import { BaseSQLiteDatabase, SQLiteTableFn } from "drizzle-orm/sqlite-core"
import { mySqlDrizzleAdapter } from "./lib/mysql.js"
import { pgDrizzleAdapter } from "./lib/pg.js"
import { SQLiteDrizzleAdapter } from "./lib/sqlite.js"
import {
isMySqlDatabase,
isPgDatabase,
isSQLiteDatabase,
SqlFlavorOptions,
TableFn,
} from "./lib/utils.js"
import { SqlFlavorOptions, TableFn } from "./lib/utils.js"
import { is } from "drizzle-orm"
import type { Adapter } from "@auth/core/adapters"
@@ -260,18 +255,15 @@ export function DrizzleAdapter<SqlFlavor extends SqlFlavorOptions>(
db: SqlFlavor,
table?: TableFn<SqlFlavor>
): Adapter {
if (isMySqlDatabase(db)) {
// We need to cast to unknown since the type overlaps (PScale is MySQL based)
if (is(db, MySqlDatabase)) {
return mySqlDrizzleAdapter(db, table as MySqlTableFn)
}
if (isPgDatabase(db)) {
} else if (is(db, PgDatabase)) {
return pgDrizzleAdapter(db, table as PgTableFn)
}
if (isSQLiteDatabase(db)) {
} else if (is(db, BaseSQLiteDatabase)) {
return SQLiteDrizzleAdapter(db, table as SQLiteTableFn)
}
throw new Error("Unsupported database type in Auth.js Drizzle adapter.")
throw new Error(
`Unsupported database type (${typeof db}) in Auth.js Drizzle adapter.`
)
}

View File

@@ -6,10 +6,10 @@ import {
primaryKey,
varchar,
MySqlTableFn,
MySqlDatabase,
} from "drizzle-orm/mysql-core"
import type { Adapter, AdapterAccount } from "@auth/core/adapters"
import type { MySql2Database } from "drizzle-orm/mysql2"
export function createTables(mySqlTable: MySqlTableFn) {
const users = mySqlTable("user", {
@@ -77,7 +77,7 @@ export function createTables(mySqlTable: MySqlTableFn) {
export type DefaultSchema = ReturnType<typeof createTables>
export function mySqlDrizzleAdapter(
client: MySql2Database<Record<string, never>>,
client: InstanceType<typeof MySqlDatabase>,
tableFn = defaultMySqlTableFn
): Adapter {
const { users, accounts, sessions, verificationTokens } =
@@ -164,10 +164,7 @@ export function mySqlDrizzleAdapter(
.then((res) => res[0])
},
async linkAccount(rawAccount) {
await client
.insert(accounts)
.values(rawAccount)
.then((res) => res[0])
await client.insert(accounts).values(rawAccount)
},
async getUserByAccount(account) {
const dbAccount =

View File

@@ -6,9 +6,9 @@ import {
primaryKey,
integer,
PgTableFn,
PgDatabase,
} from "drizzle-orm/pg-core"
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js"
import type { Adapter, AdapterAccount } from "@auth/core/adapters"
export function createTables(pgTable: PgTableFn) {
@@ -68,7 +68,7 @@ export function createTables(pgTable: PgTableFn) {
export type DefaultSchema = ReturnType<typeof createTables>
export function pgDrizzleAdapter(
client: PostgresJsDatabase<Record<string, never>>,
client: InstanceType<typeof PgDatabase>,
tableFn = defaultPgTableFn
): Adapter {
const { users, accounts, sessions, verificationTokens } =

View File

@@ -67,7 +67,7 @@ export function createTables(sqliteTable: SQLiteTableFn) {
export type DefaultSchema = ReturnType<typeof createTables>
export function SQLiteDrizzleAdapter(
client: BaseSQLiteDatabase<any, any>,
client: InstanceType<typeof BaseSQLiteDatabase>,
tableFn = defaultSqliteTableFn
): Adapter {
const { users, accounts, sessions, verificationTokens } =

View File

@@ -39,17 +39,3 @@ export type TableFn<Flavor> = Flavor extends AnyMySqlDatabase
: Flavor extends AnySQLiteDatabase
? SQLiteTableFn
: AnySQLiteTable
export function isMySqlDatabase(
db: any
): db is MySqlDatabase<any, any, any, any> {
return db instanceof MySqlDatabase
}
export function isPgDatabase(db: any): db is PgDatabase<any, any, any> {
return db instanceof PgDatabase
}
export function isSQLiteDatabase(db: any): db is AnySQLiteDatabase {
return db instanceof BaseSQLiteDatabase
}

View File

@@ -1,5 +1,5 @@
{
"extends": "@next-auth/tsconfig/tsconfig.base.json",
"extends": "@auth/tsconfig/tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",

View File

@@ -1,7 +1,7 @@
{
"name": "@auth/dynamodb-adapter",
"repository": "https://github.com/nextauthjs/next-auth",
"version": "1.0.1",
"version": "1.0.2",
"description": "AWS DynamoDB adapter for next-auth.",
"keywords": [
"next-auth",
@@ -49,8 +49,8 @@
"devDependencies": {
"@aws-sdk/client-dynamodb": "^3.36.1",
"@aws-sdk/lib-dynamodb": "^3.36.1",
"@next-auth/adapter-test": "workspace:*",
"@next-auth/tsconfig": "workspace:*",
"@auth/adapter-test": "workspace:*",
"@auth/tsconfig": "workspace:*",
"@shelf/jest-dynamodb": "^2.1.0",
"jest": "^27.4.3"
},

View File

@@ -56,8 +56,8 @@ export interface DynamoDBAdapterOptions {
*
* const config: DynamoDBClientConfig = {
* credentials: {
* accessKeyId: process.env.NEXT_AUTH_AWS_ACCESS_KEY as string,
* secretAccessKey: process.env.NEXT_AUTH_AWS_SECRET_KEY as string,
* accessKeyId: process.env.NEXT_AUTH_AWS_ACCESS_KEY,
* secretAccessKey: process.env.NEXT_AUTH_AWS_SECRET_KEY,
* },
* region: process.env.NEXT_AUTH_AWS_REGION,
* };

View File

@@ -1,7 +1,7 @@
import { DynamoDB } from "@aws-sdk/client-dynamodb"
import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
import { DynamoDBAdapter } from "../src"
import { runBasicTests } from "@next-auth/adapter-test"
import { runBasicTests } from "@auth/adapter-test"
import { format } from "../src/"
const config = {
endpoint: "http://127.0.0.1:8000",

View File

@@ -1,5 +1,5 @@
{
"extends": "@next-auth/tsconfig/tsconfig.base.json",
"extends": "@auth/tsconfig/tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",

View File

@@ -0,0 +1,28 @@
<p align="center">
<br/>
<a href="https://authjs.dev" target="_blank">
<img height="64px" src="https://authjs.dev/img/logo/logo-sm.png" />
</a>
<a href="https://www.edgedb.com/" target="_blank">
<img height="64px" src="https://authjs.dev/img/adapters/edgedb.svg"/>
</a>
<h3 align="center"><b>Edge DB Adapter</b> - NextAuth.js / Auth.js</a></h3>
<p align="center" style="align: center;">
<a href="https://npm.im/@auth/edgedb-adapter">
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
</a>
<a href="https://npm.im/@auth/edgedb-adapter">
<img alt="npm" src="https://img.shields.io/npm/v/@auth/edgedb-adapter?color=green&label=@auth/edgedb-adapter&style=flat-square">
</a>
<a href="https://www.npmtrends.com/@auth/edgedb-adapter">
<img src="https://img.shields.io/npm/dm/@auth/edgedb-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
</a>
<a href="https://github.com/nextauthjs/next-auth/stargazers">
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="Github Stars" />
</a>
</p>
</p>
---
Check out the documentation at [authjs.dev](https://authjs.dev/reference/adapter/edgedb).

View File

@@ -0,0 +1,4 @@
<svg style="color:#1F8AED" width="140" height="114" viewBox="0 0 140 114" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M118.58 56.966C118.58 66.6274 114.706 68.3592 110.377 68.3592H101.171V45.5728H110.377C114.706 45.5728 118.58 47.3046 118.58 56.966ZM113.887 56.966C113.887 50.2212 111.836 49.9022 108.874 49.9022H106.003V64.0298H108.874C111.836 64.0298 113.887 63.7108 113.887 56.966ZM65.1234 68.3592V45.5728H79.6155V49.9022H69.9541V54.5507H77.2458V58.8345H69.9541V64.0298H79.6155V68.3592H65.1234ZM87.7282 113.932H92.5589V0H87.7282V113.932ZM128.242 58.242V64.0298H132.252C134.758 64.0298 135.396 62.3892 135.396 61.1587C135.396 60.2017 134.941 58.242 131.523 58.242H128.242ZM128.242 49.9022V54.2317H131.523C133.391 54.2317 134.485 53.4113 134.485 52.0442C134.485 50.677 133.391 49.9022 131.523 49.9022H128.242ZM123.411 45.5728H132.708C137.585 45.5728 139.043 48.9908 139.043 51.4517C139.043 53.7304 137.585 55.371 136.582 55.8267C139.499 57.2395 140 60.1105 140 61.5689C140 63.4829 139.043 68.3592 132.708 68.3592H123.411V45.5728ZM37.3702 56.966C37.3702 66.6274 33.4966 68.3592 29.1671 68.3592H19.9614V45.5728H29.1671C33.4966 45.5728 37.3702 47.3046 37.3702 56.966ZM51.5885 64.2121C54.0495 64.2121 55.3255 63.3918 55.7812 62.8449V60.3384H51.862V56.4191H59.6549V65.4881C58.9713 66.5363 55.2344 68.5871 51.8164 68.5871C46.211 68.5871 41.4714 66.3996 41.4714 56.7381C41.4714 47.0767 46.2565 45.345 50.5859 45.345C57.3763 45.345 59.0625 48.8996 59.6094 52.0442L55.5989 52.9556C55.3711 51.4973 54.095 49.6744 51.1784 49.6744C48.2162 49.6744 46.1654 49.9934 46.1654 56.7381C46.1654 63.4829 48.3073 64.2121 51.5885 64.2121ZM32.6756 56.966C32.6756 50.2212 30.6248 49.9022 27.6626 49.9022H24.7915V64.0298H27.6626C30.6248 64.0298 32.6756 63.7108 32.6756 56.966ZM0 68.3592V45.5728H14.4921V49.9022H4.83072V54.5507H12.1224V58.8345H4.83072V64.0298H14.4921V68.3592H0Z" fill="currentColor">
</path>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,55 @@
{
"name": "@auth/edgedb-adapter",
"version": "0.2.0",
"description": "EdgeDB adapter for next-auth.",
"homepage": "https://authjs.dev",
"repository": "https://github.com/nextauthjs/next-auth",
"bugs": {
"url": "https://github.com/nextauthjs/next-auth/issues"
},
"author": "Bruno Crosier",
"type": "module",
"types": "./index.d.ts",
"files": [
"*.d.ts*",
"*.js",
"lib",
"src"
],
"exports": {
".": {
"types": "./index.d.ts",
"import": "./index.js"
}
},
"license": "ISC",
"keywords": [
"next-auth",
"next.js",
"oauth",
"edgedb"
],
"private": false,
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "tsc",
"test": "jest"
},
"peerDependencies": {
"edgedb": "^1.0.1",
"@auth/core": "^0.3.0"
},
"devDependencies": {
"@auth/adapter-test": "workspace:^0.0.0",
"@auth/tsconfig": "workspace:^0.0.0",
"jest": "^27.4.3",
"@auth/core": "workspace:*",
"typescript": "^4.7.4",
"edgedb": "^1.0.1"
},
"jest": {
"preset": "@auth/adapter-test/jest"
}
}

View File

@@ -0,0 +1,615 @@
/**
* <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", padding: 16}}>
* <p style={{fontWeight: "normal"}}>Official <a href="https://www.edgedb.com/">Edge DB</a> adapter for Auth.js / NextAuth.js.</p>
* <a href="https://www.edgedb.com/">
* <img style={{display: "block"}} src="/img/adapters/edgedb.svg" width="38" />
* </a>
* </div>
*
* ## Installation
*
* ```bash npm2yarn2pnpm
* npm install edgedb @auth/edgedb-adapter
* npm install @edgedb/generate --save-dev
* ```
*
* @module @auth/edgedb-adapter
*/
import type {
Adapter,
AdapterSession,
AdapterUser,
VerificationToken,
} 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 npm2yarn2pnpm
* 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 applications root directory. Youll 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 youre 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:
*
* ```javascript 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](/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 := .<user[is Account];
* multi link sessions := .<user[is Session];
* property createdAt -> 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
*
* Create a migration
*
* ```
* edgedb migration create
* ```
*
* Apply the migration
*
* ```
* 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
*
* ```npm2yarn2pnpm
* 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.
*
* For example
*
* ```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);
*
* // Return type:
* // {
* // id: string;
* // email: string;
* // emailVerified: Date | null;
* // image: string | null;
* // name: string | null;
* // } | null
*
* ```
*
*
* ## 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 instances 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 you are deploying to.
*
* ### Set an environment variable
*
* ```env title=".env"
* EDGEDB_DSN=edgedb://johndoe:supersecure@myhost.com:420
* ```
*
* ### Update the client
*
* ```diff 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()
* + const client = createClient({ dsn: process.env.EDGEDB_DSN })
*
* export default NextAuth({
* adapter: EdgeDBAdapter(client),
* providers: [
* GoogleProvider({
* clientId: process.env.GOOGLE_CLIENT_ID,
* clientSecret: process.env.GOOGLE_CLIENT_SECRET,
* }),
* ],
* })
* ```
*
*
*
* ### Apply migrations
*
* Use the DSN to apply migrations against your remote instance.
*
* ```bash
* edgedb migrate --dsn <your-instance-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.
*
* ```diff title="package.json"
* "scripts": {
* "dev": "next dev",
* "build": "next build",
* "start": "next start",
* "lint": "next lint",
* + "prebuild": "npx @edgedb/generate edgeql-js"
* },
* ```
*
*/
export function EdgeDBAdapter(client: Client): Adapter {
return {
async createUser({ email, emailVerified, name, image }) {
return await client.queryRequiredSingle(
`
with
image := <optional str>$image,
name := <optional str>$name,
emailVerified := <optional str>$emailVerified
select (
insert User {
email:= <str>$email,
emailVerified:= <datetime>emailVerified,
name:= name,
image:= image,
}
) {
id,
email,
emailVerified,
name,
image
}
`,
{
email,
emailVerified: emailVerified && new Date(emailVerified).toISOString(),
name,
image,
}
)
},
async getUser(id) {
return await client.querySingle<AdapterUser>(
`
select User {
id,
email,
emailVerified,
name,
image
} filter .id = <uuid>$id;
`,
{ id }
)
},
async getUserByEmail(email) {
return await client.querySingle<AdapterUser>(
`
select User {
id,
email,
emailVerified,
name,
image
} filter .email = <str>$email;
`,
{ email }
)
},
async getUserByAccount({ providerAccountId, provider }) {
return await client.querySingle<AdapterUser>(
`
with account := (
select Account
filter .providerAccountId = <str>$providerAccountId
and .provider = <str>$provider
)
select account.user {
id,
email,
image,
name,
emailVerified
}
`,
{ providerAccountId, provider }
)
},
async updateUser({ email, emailVerified, id, image, name }) {
return await client.queryRequiredSingle<AdapterUser>(
`
with
email := <optional str>$email,
emailVerified := <optional str>$emailVerified,
image := <optional str>$image,
name := <optional str>$name
select (
update User
filter .id = <uuid>$id
set {
email := email ?? .email,
emailVerified := <datetime>emailVerified ?? .emailVerified,
image := image ?? .image,
name := name ?? .name,
}
) {
id,
email,
emailVerified,
image,
name
}
`,
{
email,
emailVerified: emailVerified && new Date(emailVerified).toISOString(),
id,
image,
name,
}
)
},
async deleteUser(id) {
await client.execute(`delete User filter .id = <uuid>$id;`, { id })
},
async linkAccount({
userId,
type,
provider,
providerAccountId,
refresh_token,
access_token,
expires_at,
token_type,
scope,
id_token,
session_state,
}) {
await client.execute(
`
with
userId := <optional str>$userId,
refresh_token := <optional str>$refresh_token,
access_token := <optional str>$access_token,
expires_at := <optional str>$expires_at,
token_type := <optional str>$token_type,
scope := <optional str>$scope,
id_token := <optional str>$id_token,
session_state := <optional str>$session_state
insert Account {
type := <str>$type,
provider := <str>$provider,
providerAccountId := <str>$providerAccountId,
refresh_token := refresh_token,
access_token := access_token,
expires_at := <int64>expires_at,
token_type := token_type,
scope := scope,
id_token := id_token,
session_state := session_state,
user := (
select User filter .id = <uuid>userId
)
}
`,
{
userId,
type,
provider,
providerAccountId,
refresh_token,
access_token,
expires_at: expires_at && String(expires_at),
token_type,
scope,
id_token,
session_state,
}
)
},
async unlinkAccount({ providerAccountId, provider }) {
await client.execute(
`
delete Account filter
.providerAccountId = <str>$providerAccountId
and
.provider = <str>$provider
`,
{ providerAccountId, provider }
)
},
async createSession({ expires, sessionToken, userId }) {
return await client.queryRequiredSingle<AdapterSession>(
`
select (
insert Session {
expires := <datetime>$expires,
sessionToken := <str>$sessionToken,
user := (
select User filter .id = <uuid>$userId
)
}
) {
expires,
sessionToken,
userId
};
`,
{ expires, sessionToken, userId }
)
},
async getSessionAndUser(sessionToken) {
const sessionAndUser = await client.querySingle<
AdapterSession & { user: AdapterUser }
>(
`
select Session {
userId,
id,
expires,
sessionToken,
user: {
id,
email,
emailVerified,
image,
name
}
} filter .sessionToken = <str>$sessionToken;
`,
{ sessionToken }
)
if (!sessionAndUser) {
return null
}
const { user, ...session } = sessionAndUser
if (!user || !session) {
return null
}
return {
user,
session,
}
},
async updateSession({ sessionToken, expires, userId }) {
return await client.querySingle<AdapterSession>(
`
with
sessionToken := <optional str>$sessionToken,
expires := <optional str>$expires,
userId := <optional str>$userId,
user := (
select User filter .id = <uuid>userId
)
select (
update Session
filter .sessionToken = <str>$sessionToken
set {
sessionToken := sessionToken ?? .sessionToken,
expires := <datetime>expires ?? .expires,
user := user ?? .user
}
) {
sessionToken,
userId,
expires
}
`,
{
sessionToken,
expires: expires && new Date(expires).toISOString(),
userId,
}
)
},
async deleteSession(sessionToken) {
await client.query(
`delete Session filter .sessionToken = <str>$sessionToken`,
{ sessionToken }
)
},
async createVerificationToken({ identifier, expires, token }) {
const createdVerificationToken =
await client.querySingle<VerificationToken>(
`
select (
insert VerificationToken {
identifier := <str>$identifier,
expires := <datetime>$expires,
token := <str>$token,
}
) {
identifier,
expires,
token
}
`,
{ identifier, expires, token }
)
return createdVerificationToken
},
async useVerificationToken({ token, identifier }) {
const verificationToken = await client.querySingle<VerificationToken>(
`
select (
delete VerificationToken filter .token = <str>$token
and
.identifier = <str>$identifier
) {
identifier,
expires,
token
}
`,
{ token, identifier }
)
if (verificationToken && "id" in verificationToken) {
delete verificationToken.id
}
return verificationToken
},
}
}

View File

@@ -0,0 +1,91 @@
import { runBasicTests } from "@auth/adapter-test"
import { EdgeDBAdapter } from "../src"
import { createClient } from "edgedb"
if (process.env.CI) {
// TODO: Fix this
test('Skipping EdgeDBAdapter tests in CI because of "Request failed" errors. Should revisit', () => {
expect(true).toBe(true)
})
process.exit(0)
}
const client = createClient();
runBasicTests({
adapter: EdgeDBAdapter(client),
db: {
connect: async () => {
await client.query(`
delete User;
delete Account;
delete Session;
delete VerificationToken;
`)
},
disconnect: async () => {
await client.query(`
delete User;
delete Account;
delete Session;
delete VerificationToken;
`)
},
user: async (id) => {
return await client.querySingle(`
select User {
id,
email,
emailVerified,
name,
image
} filter .id = <uuid>$id
`, { id })
},
account: async ({ providerAccountId, provider }) => {
return await client.querySingle(`
select Account {
provider,
providerAccountId,
type,
access_token,
expires_at,
id_token,
refresh_token,
token_type,
scope,
session_state,
id,
userId
}
filter
.providerAccountId = <str>$providerAccountId
and
.provider = <str>$provider
`, { providerAccountId, provider })
},
session: async (sessionToken) => {
return await client.querySingle(`
select Session {
userId,
id,
expires,
sessionToken,
}
filter .sessionToken = <str>$sessionToken
`, { sessionToken })
},
async verificationToken({ token, identifier }) {
return await client.querySingle(`
select VerificationToken {
identifier,
expires,
token,
}
filter .token = <str>$token
and
.identifier = <str>$identifier
`, { token, identifier })
},
},
})

View File

@@ -0,0 +1,20 @@
{
"extends": "@auth/tsconfig/tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",
"isolatedModules": true,
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "node",
"outDir": ".",
"rootDir": "src",
"skipDefaultLibCheck": true,
"strictNullChecks": true,
"stripInternal": true,
"declarationMap": true,
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["*.js", "*.d.ts"]
}

View File

@@ -51,12 +51,12 @@
},
"devDependencies": {
"@fauna-labs/fauna-schema-migrate": "^2.1.3",
"@next-auth/adapter-test": "workspace:*",
"@next-auth/tsconfig": "workspace:*",
"@auth/adapter-test": "workspace:*",
"@auth/tsconfig": "workspace:*",
"faunadb": "^4.3.0",
"jest": "^27.4.3"
},
"jest": {
"preset": "@next-auth/adapter-test/jest"
"preset": "@auth/adapter-test/jest"
}
}
}

View File

@@ -1,5 +1,5 @@
import { collections, FaunaAdapter, format, indexes, query } from "../src"
import { runBasicTests } from "@next-auth/adapter-test"
import { runBasicTests } from "@auth/adapter-test"
import { Client as FaunaClient, Get, Match, Ref } from "faunadb"
const client = new FaunaClient({

View File

@@ -1,5 +1,5 @@
{
"extends": "@next-auth/tsconfig/tsconfig.base.json",
"extends": "@auth/tsconfig/tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",

View File

@@ -48,10 +48,10 @@
"firebase-admin": "^11.4.1"
},
"devDependencies": {
"@next-auth/adapter-test": "workspace:*",
"@next-auth/tsconfig": "workspace:*",
"@auth/adapter-test": "workspace:*",
"@auth/tsconfig": "workspace:*",
"firebase-admin": "^11.4.1",
"firebase-tools": "^11.16.1",
"jest": "^29.3.1"
}
}
}

View File

@@ -1,4 +1,4 @@
import { runBasicTests } from "@next-auth/adapter-test"
import { runBasicTests } from "@auth/adapter-test"
import { FirestoreAdapter, type FirebaseAdapterConfig } from "../src"
import {

View File

@@ -1,4 +1,4 @@
import config from "@next-auth/adapter-test/jest/jest-preset.js"
import config from "@auth/adapter-test/jest/jest-preset.js"
//TODO: update rest of the packages to Jest 29+
const {testURL, ...rest} = config

View File

@@ -1,5 +1,5 @@
{
"extends": "@next-auth/tsconfig/tsconfig.base.json",
"extends": "@auth/tsconfig/tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",

View File

@@ -40,8 +40,8 @@
"kysely": "^0.26.1"
},
"devDependencies": {
"@next-auth/adapter-test": "workspace:*",
"@next-auth/tsconfig": "workspace:*",
"@auth/adapter-test": "workspace:*",
"@auth/tsconfig": "workspace:*",
"@types/better-sqlite3": "^7.6.3",
"@types/pg": "^8.6.5",
"better-sqlite3": "^8.2.0",
@@ -51,6 +51,6 @@
"pg": "^8.10.0"
},
"jest": {
"preset": "@next-auth/adapter-test/jest"
"preset": "@auth/adapter-test/jest"
}
}
}

View File

@@ -1,4 +1,4 @@
import { runBasicTests } from "@next-auth/adapter-test"
import { runBasicTests } from "@auth/adapter-test"
import { Pool } from "pg"
import {
Kysely,

View File

@@ -1,5 +1,5 @@
{
"extends": "@next-auth/tsconfig/tsconfig.base.json",
"extends": "@auth/tsconfig/tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",

View File

@@ -46,14 +46,14 @@
"devDependencies": {
"@mikro-orm/core": "^5",
"@mikro-orm/sqlite": "^5",
"@next-auth/adapter-test": "workspace:*",
"@next-auth/tsconfig": "workspace:*",
"@auth/adapter-test": "workspace:*",
"@auth/tsconfig": "workspace:*",
"jest": "^29"
},
"dependencies": {
"@auth/core": "workspace:*"
},
"jest": {
"preset": "@next-auth/adapter-test/jest"
"preset": "@auth/adapter-test/jest"
}
}
}

View File

@@ -13,7 +13,7 @@ import {
Options,
types,
} from "@mikro-orm/core"
import { runBasicTests } from "@next-auth/adapter-test"
import { runBasicTests } from "@auth/adapter-test"
globalThis.crypto ??= require("node:crypto").webcrypto

View File

@@ -1,5 +1,5 @@
{
"extends": "@next-auth/tsconfig/tsconfig.base.json",
"extends": "@auth/tsconfig/tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",

View File

@@ -1,6 +1,6 @@
{
"name": "@auth/mongodb-adapter",
"version": "1.0.0",
"version": "2.0.0",
"description": "MongoDB adapter for Auth.js",
"homepage": "https://authjs.dev",
"repository": "https://github.com/nextauthjs/next-auth",
@@ -42,15 +42,15 @@
"@auth/core": "workspace:*"
},
"peerDependencies": {
"mongodb": "^5 || ^4"
"mongodb": "^6"
},
"devDependencies": {
"@next-auth/adapter-test": "workspace:*",
"@next-auth/tsconfig": "workspace:*",
"@auth/adapter-test": "workspace:*",
"@auth/tsconfig": "workspace:*",
"jest": "^27.4.3",
"mongodb": "^5.1.0"
"mongodb": "^6.0.0"
},
"jest": {
"preset": "@next-auth/adapter-test/jest"
"preset": "@auth/adapter-test/jest"
}
}

View File

@@ -193,7 +193,7 @@ export function MongoDBAdapter(
await db
).U.findOneAndUpdate({ _id }, { $set: user }, { returnDocument: "after" })
return from<AdapterUser>(result.value!)
return from<AdapterUser>(result!)
},
async deleteUser(id) {
const userId = _id(id)
@@ -210,7 +210,7 @@ export function MongoDBAdapter(
return account
},
async unlinkAccount(provider_providerAccountId) {
const { value: account } = await (
const account = await (
await db
).A.findOneAndDelete(provider_providerAccountId)
return from<AdapterAccount>(account!)
@@ -235,17 +235,17 @@ export function MongoDBAdapter(
async updateSession(data) {
const { _id, ...session } = to<AdapterSession>(data)
const result = await (
const updatedSession = await (
await db
).S.findOneAndUpdate(
{ sessionToken: session.sessionToken },
{ $set: session },
{ returnDocument: "after" }
)
return from<AdapterSession>(result.value!)
return from<AdapterSession>(updatedSession!)
},
async deleteSession(sessionToken) {
const { value: session } = await (
const session = await (
await db
).S.findOneAndDelete({
sessionToken,
@@ -257,14 +257,13 @@ export function MongoDBAdapter(
return data
},
async useVerificationToken(identifier_token) {
const { value: verificationToken } = await (
const verificationToken = await (
await db
).V.findOneAndDelete(identifier_token)
if (!verificationToken) return null
// @ts-expect-error
delete verificationToken._id
return verificationToken
const { _id, ...rest } = verificationToken;
return rest;
},
}
}

View File

@@ -1,4 +1,4 @@
import { runBasicTests } from "@next-auth/adapter-test"
import { runBasicTests } from "@auth/adapter-test"
import { defaultCollections, format, MongoDBAdapter, _id } from "../src"
import { MongoClient } from "mongodb"
const name = "custom-test"

View File

@@ -1,4 +1,4 @@
import { runBasicTests } from "@next-auth/adapter-test"
import { runBasicTests } from "@auth/adapter-test"
import { defaultCollections, format, MongoDBAdapter, _id } from "../src"
import { MongoClient } from "mongodb"

View File

@@ -1,5 +1,5 @@
{
"extends": "@next-auth/tsconfig/tsconfig.base.json",
"extends": "@auth/tsconfig/tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",

View File

@@ -44,8 +44,8 @@
"neo4j-driver": "^4.0.0 || ^5.7.0"
},
"devDependencies": {
"@next-auth/adapter-test": "workspace:*",
"@next-auth/tsconfig": "workspace:*",
"@auth/adapter-test": "workspace:*",
"@auth/tsconfig": "workspace:*",
"@types/uuid": "^8.3.3",
"jest": "^27.4.3",
"neo4j-driver": "^5.7.0"
@@ -54,6 +54,6 @@
"@auth/core": "workspace:*"
},
"jest": {
"preset": "@next-auth/adapter-test/jest"
"preset": "@auth/adapter-test/jest"
}
}
}

View File

@@ -1,5 +1,5 @@
import * as neo4j from "neo4j-driver"
import { runBasicTests } from "@next-auth/adapter-test"
import { runBasicTests } from "@auth/adapter-test"
import statements from "./resources/statements"
import { Neo4jAdapter, format } from "../src"

View File

@@ -1,5 +1,5 @@
{
"extends": "@next-auth/tsconfig/tsconfig.base.json",
"extends": "@auth/tsconfig/tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",

View File

@@ -45,8 +45,8 @@
"@auth/core": "workspace:*"
},
"devDependencies": {
"@next-auth/adapter-test": "workspace:*",
"@next-auth/tsconfig": "workspace:*",
"@auth/adapter-test": "workspace:*",
"@auth/tsconfig": "workspace:*",
"@types/pouchdb": "^6.4.0",
"jest": "^27.4.3",
"pouchdb": "^8.0.1",
@@ -54,6 +54,6 @@
"pouchdb-find": "^8.0.1"
},
"jest": {
"preset": "@next-auth/adapter-test/jest"
"preset": "@auth/adapter-test/jest"
}
}
}

View File

@@ -1,4 +1,4 @@
import { runBasicTests } from "@next-auth/adapter-test"
import { runBasicTests } from "@auth/adapter-test"
import {
createIndexes,
PouchDBAdapter,

View File

@@ -1,5 +1,5 @@
{
"extends": "@next-auth/tsconfig/tsconfig.base.json",
"extends": "@auth/tsconfig/tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",

View File

@@ -1,6 +1,6 @@
{
"name": "@auth/prisma-adapter",
"version": "1.0.1",
"version": "1.0.2",
"description": "Prisma adapter for Auth.js",
"homepage": "https://authjs.dev/reference/adapter/prisma",
"repository": "https://github.com/nextauthjs/next-auth",
@@ -51,17 +51,17 @@
"@auth/core": "workspace:*"
},
"peerDependencies": {
"@prisma/client": ">=2.26.0 || >=3 || >=4"
"@prisma/client": ">=2.26.0 || >=3 || >=4 || >=5"
},
"devDependencies": {
"@next-auth/adapter-test": "workspace:*",
"@next-auth/tsconfig": "workspace:*",
"@prisma/client": "^4.15.0",
"@auth/adapter-test": "workspace:*",
"@auth/tsconfig": "workspace:*",
"@prisma/client": "^5.2.0",
"jest": "^27.4.3",
"mongodb": "^4.4.0",
"prisma": "^4.15.0"
"mongodb": "^4.17.0",
"prisma": "^5.2.0"
},
"jest": {
"preset": "@next-auth/adapter-test/jest"
"preset": "@auth/adapter-test/jest"
}
}

Some files were not shown because too many files have changed in this diff Show More