mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
12 Commits
@auth/soli
...
fix/improv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f42ef7cc62 | ||
|
|
35a708a2c3 | ||
|
|
4f919ca76f | ||
|
|
036e34b4b6 | ||
|
|
d2288ee4cc | ||
|
|
5a6f76bf2c | ||
|
|
15bed6260c | ||
|
|
1423733d61 | ||
|
|
77d8f47f51 | ||
|
|
3120d28299 | ||
|
|
e6a320bb0f | ||
|
|
7d4d436efe |
@@ -29,7 +29,7 @@ const Home: ParentComponent = () => {
|
|||||||
</A>{" "}
|
</A>{" "}
|
||||||
with{" "}
|
with{" "}
|
||||||
<A
|
<A
|
||||||
href="https://authjs.dev/reference/solid-start/modules/main"
|
href="https://authjs.dev/reference/solidstart"
|
||||||
class="text-blue-500 underline font-bold"
|
class="text-blue-500 underline font-bold"
|
||||||
>
|
>
|
||||||
SolidStart Auth
|
SolidStart Auth
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ id: dynamodb
|
|||||||
title: DynamoDB
|
title: DynamoDB
|
||||||
---
|
---
|
||||||
|
|
||||||
This is the AWS DynamoDB Adapter for next-auth. This package can only be used in conjunction with the primary next-auth package. It is not a standalone package.
|
This is the AWS DynamoDB Adapter for `next-auth`. This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
|
||||||
|
|
||||||
By default, the adapter expects a table with a partition key `pk` and a sort key `sk`, as well as a global secondary index named `GSI1` with `GSI1PK` as partition key and `GSI1SK` as sorting key. To automatically delete sessions and verification requests after they expire using [dynamodb TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html) you should [enable the TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/time-to-live-ttl-how-to.html) with attribute name 'expires'. You can set whatever you want as the table name and the billing method.
|
By default, the adapter expects a table with a partition key `pk` and a sort key `sk`, as well as a global secondary index named `GSI1` with `GSI1PK` as partition key and `GSI1SK` as sorting key. To automatically delete sessions and verification requests after they expire using [dynamodb TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html) you should [enable the TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/time-to-live-ttl-how-to.html) with attribute name 'expires'. You can set whatever you want as the table name and the billing method.
|
||||||
|
|
||||||
@@ -11,10 +11,10 @@ You can find the full schema in the table structure section below.
|
|||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
1. Install `next-auth` and `@next-auth/dynamodb-adapter`
|
1. Install `next-auth`, `@next-auth/dynamodb-adapter`, `@aws-sdk/client-dynamodb` and `@aws-sdk/lib-dynamodb`
|
||||||
|
|
||||||
```bash npm2yarn
|
```bash npm2yarn2pnpm
|
||||||
npm install next-auth @next-auth/dynamodb-adapter
|
npm install next-auth @next-auth/dynamodb-adapter @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
|
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
|
||||||
@@ -23,7 +23,7 @@ You need to pass `DynamoDBDocument` client from the modular [`aws-sdk`](https://
|
|||||||
The default table name is `next-auth`, but you can customise that by passing `{ tableName: 'your-table-name' }` as the second parameter in the adapter.
|
The default table name is `next-auth`, but you can customise that by passing `{ tableName: 'your-table-name' }` as the second parameter in the adapter.
|
||||||
|
|
||||||
```javascript title="pages/api/auth/[...nextauth].js"
|
```javascript title="pages/api/auth/[...nextauth].js"
|
||||||
import { DynamoDB } from "@aws-sdk/client-dynamodb"
|
import { DynamoDB, DynamoDBClientConfig } from "@aws-sdk/client-dynamodb"
|
||||||
import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
|
import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
|
||||||
import NextAuth from "next-auth";
|
import NextAuth from "next-auth";
|
||||||
import Providers from "next-auth/providers";
|
import Providers from "next-auth/providers";
|
||||||
@@ -73,7 +73,7 @@ The table respects the single table design pattern. This has many advantages:
|
|||||||
|
|
||||||
- Only one table to manage, monitor and provision.
|
- Only one table to manage, monitor and provision.
|
||||||
- Querying relations is faster than with multi-table schemas (for eg. retrieving all sessions for a user).
|
- Querying relations is faster than with multi-table schemas (for eg. retrieving all sessions for a user).
|
||||||
- Only one table needs to be replicated, if you want to go multi-region.
|
- Only one table needs to be replicated if you want to go multi-region.
|
||||||
|
|
||||||
> This schema is adapted for use in DynamoDB and based upon our main [schema](/reference/adapters/models)
|
> This schema is adapted for use in DynamoDB and based upon our main [schema](/reference/adapters/models)
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ new dynamodb.Table(this, `NextAuthTable`, {
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively you can use this cloudformation template:
|
Alternatively, you can use this cloudformation template:
|
||||||
|
|
||||||
```yaml title=cloudformation.yaml
|
```yaml title=cloudformation.yaml
|
||||||
NextAuthTable:
|
NextAuthTable:
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ const docusaurusConfig = {
|
|||||||
title: "Auth.js",
|
title: "Auth.js",
|
||||||
logo: {
|
logo: {
|
||||||
alt: "Auth.js Logo",
|
alt: "Auth.js Logo",
|
||||||
src: "img/logo/logo-xs.png",
|
src: "img/logo/logo-xs.webp",
|
||||||
},
|
},
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
@@ -101,7 +101,7 @@ const docusaurusConfig = {
|
|||||||
announcementBar: {
|
announcementBar: {
|
||||||
id: "new-major-announcement",
|
id: "new-major-announcement",
|
||||||
content:
|
content:
|
||||||
"<a target='_blank' rel='noopener noreferrer' href='https://next-auth.js.org'>NextAuth.js</a> is becoming Auth.js! 🎉 We're creating Authentication for the Web. Everyone included. Starting with SvelteKit, check out the docs <a href='/reference/sveltekit'>here</a>.",
|
"<a target='_blank' rel='noopener noreferrer' href='https://next-auth.js.org'>NextAuth.js</a> is becoming Auth.js! 🎉 We're creating Authentication for the Web. Everyone included. Starting with SvelteKit, check out <a href='/reference/sveltekit'>the docs</a>.",
|
||||||
backgroundColor: "#000",
|
backgroundColor: "#000",
|
||||||
textColor: "#fff",
|
textColor: "#fff",
|
||||||
},
|
},
|
||||||
@@ -121,6 +121,7 @@ const docusaurusConfig = {
|
|||||||
alt="Powered by Vercel"
|
alt="Powered by Vercel"
|
||||||
style="margin-top: 8px"
|
style="margin-top: 8px"
|
||||||
height="32"
|
height="32"
|
||||||
|
width="167"
|
||||||
src="https://raw.githubusercontent.com/nextauthjs/next-auth/main/docs/static/img/powered-by-vercel.svg"
|
src="https://raw.githubusercontent.com/nextauthjs/next-auth/main/docs/static/img/powered-by-vercel.svg"
|
||||||
/>
|
/>
|
||||||
</a>`,
|
</a>`,
|
||||||
@@ -181,7 +182,10 @@ const docusaurusConfig = {
|
|||||||
lastVersion: "current",
|
lastVersion: "current",
|
||||||
showLastUpdateAuthor: true,
|
showLastUpdateAuthor: true,
|
||||||
showLastUpdateTime: true,
|
showLastUpdateTime: true,
|
||||||
remarkPlugins: [require("@sapphire/docusaurus-plugin-npm2yarn2pnpm").npm2yarn2pnpm, require("remark-github")],
|
remarkPlugins: [
|
||||||
|
require("@sapphire/docusaurus-plugin-npm2yarn2pnpm").npm2yarn2pnpm,
|
||||||
|
require("remark-github"),
|
||||||
|
],
|
||||||
versions: {
|
versions: {
|
||||||
current: {
|
current: {
|
||||||
label: "experimental",
|
label: "experimental",
|
||||||
@@ -201,7 +205,15 @@ const docusaurusConfig = {
|
|||||||
...typedocConfig,
|
...typedocConfig,
|
||||||
id: "core",
|
id: "core",
|
||||||
plugin: ["./tyepdoc"],
|
plugin: ["./tyepdoc"],
|
||||||
entryPoints: ["index.ts", "adapters.ts", "errors.ts", "jwt.ts", "types.ts"].map((e) => `${coreSrc}/${e}`).concat(providers),
|
entryPoints: [
|
||||||
|
"index.ts",
|
||||||
|
"adapters.ts",
|
||||||
|
"errors.ts",
|
||||||
|
"jwt.ts",
|
||||||
|
"types.ts",
|
||||||
|
]
|
||||||
|
.map((e) => `${coreSrc}/${e}`)
|
||||||
|
.concat(providers),
|
||||||
tsconfig: "../packages/core/tsconfig.json",
|
tsconfig: "../packages/core/tsconfig.json",
|
||||||
out: "reference/03-core",
|
out: "reference/03-core",
|
||||||
watch: process.env.TYPEDOC_WATCH,
|
watch: process.env.TYPEDOC_WATCH,
|
||||||
@@ -214,7 +226,9 @@ const docusaurusConfig = {
|
|||||||
...typedocConfig,
|
...typedocConfig,
|
||||||
id: "sveltekit",
|
id: "sveltekit",
|
||||||
plugin: ["./tyepdoc"],
|
plugin: ["./tyepdoc"],
|
||||||
entryPoints: ["index.ts", "client.ts"].map((e) => `../packages/frameworks-sveltekit/src/lib/${e}`),
|
entryPoints: ["index.ts", "client.ts"].map(
|
||||||
|
(e) => `../packages/frameworks-sveltekit/src/lib/${e}`
|
||||||
|
),
|
||||||
tsconfig: "../packages/frameworks-sveltekit/tsconfig.json",
|
tsconfig: "../packages/frameworks-sveltekit/tsconfig.json",
|
||||||
out: "reference/04-sveltekit",
|
out: "reference/04-sveltekit",
|
||||||
watch: process.env.TYPEDOC_WATCH,
|
watch: process.env.TYPEDOC_WATCH,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"mdx-mermaid": "1.2.2",
|
"mdx-mermaid": "1.2.2",
|
||||||
"mermaid": "9.0.1",
|
"mermaid": "9.0.1",
|
||||||
|
"next-auth": "workspace:*",
|
||||||
"prism-react-renderer": "1.3.5",
|
"prism-react-renderer": "1.3.5",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
|||||||
@@ -58,9 +58,9 @@ module.exports = {
|
|||||||
label: "@auth/solid-start",
|
label: "@auth/solid-start",
|
||||||
link: {
|
link: {
|
||||||
type: "doc",
|
type: "doc",
|
||||||
id: "reference/solid-start/index",
|
id: "reference/solidstart/index",
|
||||||
},
|
},
|
||||||
items: ["reference/solid-start/client", "reference/solid-start/protected"],
|
items: ["reference/solidstart/client", "reference/solidstart/protected"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "category",
|
type: "category",
|
||||||
|
|||||||
@@ -140,19 +140,19 @@ html[data-theme="dark"] hr {
|
|||||||
border-radius: 10rem;
|
border-radius: 10rem;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
box-shadow: 0 0 2rem rgba(0, 0, 0, 0.1);
|
box-shadow: 0 0 2rem rgba(0, 0, 0, 0.1);
|
||||||
background-image: url("/img/mesh-1.jpg");
|
background-image: url("/img/mesh-1.webp");
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-origin: center;
|
background-origin: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-main .section-features .row .col:nth-child(2) .feature-image-wrapper {
|
.home-main .section-features .row .col:nth-child(2) .feature-image-wrapper {
|
||||||
background-image: url("/img/mesh-2.jpg");
|
background-image: url("/img/mesh-2.webp");
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-origin: center;
|
background-origin: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-main .section-features .row .col:nth-child(3) .feature-image-wrapper {
|
.home-main .section-features .row .col:nth-child(3) .feature-image-wrapper {
|
||||||
background-image: url("/img/mesh-3.jpg");
|
background-image: url("/img/mesh-3.webp");
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-origin: center;
|
background-origin: center;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,11 @@
|
|||||||
margin-right: 1rem !important;
|
margin-right: 1rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar__logo {
|
||||||
|
width: 29px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar__title {
|
.navbar__title {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
margin-left: 0.2rem;
|
margin-left: 0.2rem;
|
||||||
|
|||||||
@@ -117,9 +117,11 @@ export default function Home() {
|
|||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="hero-inner">
|
<div className="hero-inner">
|
||||||
<img
|
<img
|
||||||
src="/img/logo/logo-sm.png"
|
src="/img/logo/logo-sm.webp"
|
||||||
alt="Shield with key icon"
|
alt="Shield with key icon"
|
||||||
className={styles.heroLogo}
|
className={styles.heroLogo}
|
||||||
|
height="142"
|
||||||
|
width="128"
|
||||||
/>
|
/>
|
||||||
<div className={styles.heroText}>
|
<div className={styles.heroText}>
|
||||||
<h1 className="hero__title">{siteConfig.title}</h1>
|
<h1 className="hero__title">{siteConfig.title}</h1>
|
||||||
@@ -214,9 +216,9 @@ export default function Home() {
|
|||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col col--6">
|
<div className="col col--6">
|
||||||
<div className="code">
|
<div className="code">
|
||||||
<h4 className="code-heading">
|
<div className="code-heading">
|
||||||
Next.js <span>/pages/api/auth/[...nextauth].ts</span>
|
Next.js <span>/pages/api/auth/[...nextauth].ts</span>
|
||||||
</h4>
|
</div>
|
||||||
<CodeBlock className="prism-code language-js">
|
<CodeBlock className="prism-code language-js">
|
||||||
{nextJsCode}
|
{nextJsCode}
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
@@ -224,9 +226,9 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="col col--6">
|
<div className="col col--6">
|
||||||
<div className="code">
|
<div className="code">
|
||||||
<h4 className="code-heading">
|
<div className="code-heading">
|
||||||
SvelteKit <span>/hooks.server.ts</span>
|
SvelteKit <span>/hooks.server.ts</span>
|
||||||
</h4>
|
</div>
|
||||||
<CodeBlock className="prism-code language-js">
|
<CodeBlock className="prism-code language-js">
|
||||||
{svelteKitCode}
|
{svelteKitCode}
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
@@ -234,9 +236,9 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="col col--6">
|
<div className="col col--6">
|
||||||
<div className="code">
|
<div className="code">
|
||||||
<h4 className="code-heading">
|
<div className="code-heading">
|
||||||
SolidStart <span>/routes/api/auth/[...solidauth].ts</span>
|
SolidStart <span>/routes/api/auth/[...solidauth].ts</span>
|
||||||
</h4>
|
</div>
|
||||||
<CodeBlock className="prism-code language-js">
|
<CodeBlock className="prism-code language-js">
|
||||||
{solidStartCode}
|
{solidStartCode}
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
|
|||||||
BIN
docs/static/img/logo/logo-sm.webp
vendored
Normal file
BIN
docs/static/img/logo/logo-sm.webp
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
docs/static/img/logo/logo-xs.webp
vendored
Normal file
BIN
docs/static/img/logo/logo-xs.webp
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
BIN
docs/static/img/logo/logo.webp
vendored
Normal file
BIN
docs/static/img/logo/logo.webp
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
BIN
docs/static/img/mesh-1.webp
vendored
Normal file
BIN
docs/static/img/mesh-1.webp
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
BIN
docs/static/img/mesh-2.webp
vendored
Normal file
BIN
docs/static/img/mesh-2.webp
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/static/img/mesh-3.webp
vendored
Normal file
BIN
docs/static/img/mesh-3.webp
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
@@ -60,6 +60,11 @@
|
|||||||
"destination": "https://github.com/nextauthjs/next-auth/discussions/categories/questions",
|
"destination": "https://github.com/nextauthjs/next-auth/discussions/categories/questions",
|
||||||
"permanent": true
|
"permanent": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": "/reference/solid-start/:path*",
|
||||||
|
"destination": "/reference/solidstart/:path*",
|
||||||
|
"permanent": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": "/",
|
"source": "/",
|
||||||
"has": [
|
"has": [
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
"repository": "https://github.com/nextauthjs/next-auth.git",
|
"repository": "https://github.com/nextauthjs/next-auth.git",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:app": "turbo run build --filter=next-auth-app",
|
"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=@next-auth/* --filter=@auth/* --no-deps",
|
||||||
"test": "turbo run test --concurrency=1 --filter=[HEAD^1] --filter=./packages/* --filter=!*pouchdb-* --filter=!@*upstash* --filter=!*dynamodb-*",
|
"test": "turbo run test --concurrency=1 --filter=[HEAD^1] --filter=./packages/* --filter=!*pouchdb-* --filter=!@*upstash* --filter=!*dynamodb-*",
|
||||||
"clean": "turbo run clean --no-cache",
|
"clean": "turbo run clean --no-cache",
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
"author": "Pol Marnette",
|
"author": "Pol Marnette",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
"@aws-sdk/client-dynamodb": "^3.36.1",
|
||||||
"@aws-sdk/lib-dynamodb": "^3.36.1",
|
"@aws-sdk/lib-dynamodb": "^3.36.1",
|
||||||
"next-auth": "^4"
|
"next-auth": "^4"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
"Balázs Orbán <info@balazsorban.com>",
|
"Balázs Orbán <info@balazsorban.com>",
|
||||||
"Nico Domino <yo@ndo.dev>",
|
"Nico Domino <yo@ndo.dev>",
|
||||||
"Lluis Agusti <hi@llu.lu>",
|
"Lluis Agusti <hi@llu.lu>",
|
||||||
"Thang Huu Vu <thvu@hey.com>",
|
"Thang Huu Vu <hi@thvu.dev>",
|
||||||
"Iain Collins <me@iaincollins.com"
|
"Iain Collins <me@iaincollins.com"
|
||||||
],
|
],
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,14 +1,23 @@
|
|||||||
|
interface ErrorCause extends Record<string, unknown> {}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export class AuthError extends Error {
|
export class AuthError extends Error {
|
||||||
metadata?: Record<string, unknown>
|
constructor(message: string | Error | ErrorCause, cause?: ErrorCause) {
|
||||||
constructor(message: Error | string, metadata?: Record<string, unknown>) {
|
|
||||||
if (message instanceof Error) {
|
if (message instanceof Error) {
|
||||||
super(message.message)
|
super(undefined, {
|
||||||
this.stack = message.stack
|
cause: { err: message, ...(message.cause as any), ...cause },
|
||||||
} else super(message)
|
})
|
||||||
this.name = this.constructor.name
|
} else if (typeof message === "string") {
|
||||||
this.metadata = metadata
|
if (cause instanceof Error) {
|
||||||
|
cause = { err: cause, ...(cause.cause as any) }
|
||||||
|
}
|
||||||
|
super(message, cause)
|
||||||
|
} else {
|
||||||
|
super(undefined, message)
|
||||||
|
}
|
||||||
Error.captureStackTrace?.(this, this.constructor)
|
Error.captureStackTrace?.(this, this.constructor)
|
||||||
|
this.name =
|
||||||
|
message instanceof AuthError ? message.name : this.constructor.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +37,45 @@ export class AdapterError extends AuthError {}
|
|||||||
/** @todo */
|
/** @todo */
|
||||||
export class AuthorizedCallbackError extends AuthError {}
|
export class AuthorizedCallbackError extends AuthError {}
|
||||||
|
|
||||||
/** @todo */
|
/**
|
||||||
|
* There was an error while trying to finish up authenticating the user.
|
||||||
|
* Depending on the type of provider, this could be for multiple reasons.
|
||||||
|
*
|
||||||
|
* :::tip
|
||||||
|
* Check out `[auth][details]` in the error message to know which provider failed.
|
||||||
|
* @example
|
||||||
|
* ```sh
|
||||||
|
* [auth][details]: { "provider": "github" }
|
||||||
|
* ```
|
||||||
|
* :::
|
||||||
|
*
|
||||||
|
* For an **OAuth provider**, possible causes are:
|
||||||
|
* - The user denied access to the application
|
||||||
|
* - There was an error parsing the OAuth Profile:
|
||||||
|
* Check out the provider's `profile` or `userinfo.request` method to make sure
|
||||||
|
* it correctly fetches the user's profile.
|
||||||
|
* - The `signIn` or `jwt` callback methods threw an uncaught error:
|
||||||
|
* Check the callback method implementations.
|
||||||
|
*
|
||||||
|
* For an **Email provider**, possible causes are:
|
||||||
|
* - The provided email/token combination was invalid/missing:
|
||||||
|
* Check if the provider's `sendVerificationRequest` method correctly sends the email.
|
||||||
|
* - The provided email/token combination has expired:
|
||||||
|
* Ask the user to log in again.
|
||||||
|
* - There was an error with the database:
|
||||||
|
* Check the database logs.
|
||||||
|
*
|
||||||
|
* For a **Credentials provider**, possible causes are:
|
||||||
|
* - The `authorize` method threw an uncaught error:
|
||||||
|
* Check the provider's `authorize` method.
|
||||||
|
* - The `signIn` or `jwt` callback methods threw an uncaught error:
|
||||||
|
* Check the callback method implementations.
|
||||||
|
*
|
||||||
|
* :::tip
|
||||||
|
* Check out `[auth][cause]` in the error message for more details.
|
||||||
|
* It will show the original stack trace.
|
||||||
|
* :::
|
||||||
|
*/
|
||||||
export class CallbackRouteError extends AuthError {}
|
export class CallbackRouteError extends AuthError {}
|
||||||
|
|
||||||
/** @todo */
|
/** @todo */
|
||||||
@@ -93,3 +140,10 @@ export class UnsupportedStrategy extends AuthError {}
|
|||||||
|
|
||||||
/** @todo */
|
/** @todo */
|
||||||
export class UntrustedHost extends AuthError {}
|
export class UntrustedHost extends AuthError {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user's email/token combination was invalid.
|
||||||
|
* This could be because the email/token combination was not found in the database,
|
||||||
|
* or because it token has expired. Ask the user to log in again.
|
||||||
|
*/
|
||||||
|
export class Verification extends AuthError {}
|
||||||
|
|||||||
@@ -133,7 +133,8 @@ export async function handleLogin(
|
|||||||
// with is already associated with another user, then we cannot link them
|
// with is already associated with another user, then we cannot link them
|
||||||
// and need to return an error.
|
// and need to return an error.
|
||||||
throw new AccountNotLinked(
|
throw new AccountNotLinked(
|
||||||
"The account is already associated with another user"
|
"The account is already associated with another user",
|
||||||
|
{ provider: account.provider }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// If there is no active session, but the account being signed in with is already
|
// If there is no active session, but the account being signed in with is already
|
||||||
@@ -193,7 +194,8 @@ export async function handleLogin(
|
|||||||
// want to link them in case it's not safe to do so, so instead we prompt the user
|
// want to link them in case it's not safe to do so, so instead we prompt the user
|
||||||
// to sign in via email to verify their identity and then link the accounts.
|
// to sign in via email to verify their identity and then link the accounts.
|
||||||
throw new AccountNotLinked(
|
throw new AccountNotLinked(
|
||||||
"Another account already exists with the same e-mail address"
|
"Another account already exists with the same e-mail address",
|
||||||
|
{ provider: account.provider }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { handleLogin } from "../callback-handler.js"
|
import { handleLogin } from "../callback-handler.js"
|
||||||
import { CallbackRouteError } from "../../errors.js"
|
import { CallbackRouteError, Verification } from "../../errors.js"
|
||||||
import { handleOAuth } from "../oauth/callback.js"
|
import { handleOAuth } from "../oauth/callback.js"
|
||||||
import { createHash } from "../web.js"
|
import { createHash } from "../web.js"
|
||||||
import { handleAuthorized } from "./shared.js"
|
import { handleAuthorized } from "./shared.js"
|
||||||
@@ -8,7 +8,6 @@ import type { AdapterSession } from "../../adapters.js"
|
|||||||
import type {
|
import type {
|
||||||
RequestInternal,
|
RequestInternal,
|
||||||
ResponseInternal,
|
ResponseInternal,
|
||||||
User,
|
|
||||||
InternalOptions,
|
InternalOptions,
|
||||||
} from "../../types.js"
|
} from "../../types.js"
|
||||||
import type { Cookie, SessionStore } from "../cookie.js"
|
import type { Cookie, SessionStore } from "../cookie.js"
|
||||||
@@ -154,9 +153,13 @@ export async function callback(params: {
|
|||||||
const token = query?.token as string | undefined
|
const token = query?.token as string | undefined
|
||||||
const identifier = query?.email as string | undefined
|
const identifier = query?.email as string | undefined
|
||||||
|
|
||||||
// If these are missing, the sign-in URL was manually opened without these params or the `sendVerificationRequest` method did not send the link correctly in the email.
|
|
||||||
if (!token || !identifier) {
|
if (!token || !identifier) {
|
||||||
return { redirect: `${url}/error?error=configuration`, cookies }
|
const e = new TypeError(
|
||||||
|
"Missing token or email. The sign-in URL was manually opened without token/identifier or the link was not sent correctly in the email.",
|
||||||
|
{ cause: { hasToken: !!token, hasEmail: !!identifier } }
|
||||||
|
)
|
||||||
|
e.name = "Configuration"
|
||||||
|
throw e
|
||||||
}
|
}
|
||||||
|
|
||||||
const secret = provider.secret ?? options.secret
|
const secret = provider.secret ?? options.secret
|
||||||
@@ -166,10 +169,10 @@ export async function callback(params: {
|
|||||||
token: await createHash(`${token}${secret}`),
|
token: await createHash(`${token}${secret}`),
|
||||||
})
|
})
|
||||||
|
|
||||||
const invalidInvite = !invite || invite.expires.valueOf() < Date.now()
|
const hasInvite = !!invite
|
||||||
if (invalidInvite) {
|
const expired = invite ? invite.expires.valueOf() < Date.now() : undefined
|
||||||
return { redirect: `${url}/error?error=Verification`, cookies }
|
const invalidInvite = !hasInvite || expired
|
||||||
}
|
if (invalidInvite) throw new Verification({ hasInvite, expired })
|
||||||
|
|
||||||
// @ts-expect-error -- Verified in `assertConfig`.
|
// @ts-expect-error -- Verified in `assertConfig`.
|
||||||
const profile = await getAdapterUserFromEmail(identifier, adapter)
|
const profile = await getAdapterUserFromEmail(identifier, adapter)
|
||||||
@@ -252,13 +255,11 @@ export async function callback(params: {
|
|||||||
} else if (provider.type === "credentials" && method === "POST") {
|
} else if (provider.type === "credentials" && method === "POST") {
|
||||||
const credentials = body
|
const credentials = body
|
||||||
|
|
||||||
let user: User | null
|
|
||||||
|
|
||||||
try {
|
|
||||||
// TODO: Forward the original request as is, instead of reconstructing it
|
// TODO: Forward the original request as is, instead of reconstructing it
|
||||||
// prettier-ignore
|
Object.entries(query ?? {}).forEach(([k, v]) =>
|
||||||
Object.entries(query ?? {}).forEach(([k, v]) => url.searchParams.set(k, v))
|
url.searchParams.set(k, v)
|
||||||
user = await provider.authorize(
|
)
|
||||||
|
const user = await provider.authorize(
|
||||||
credentials,
|
credentials,
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
new Request(url, { headers, method, body: JSON.stringify(body) })
|
new Request(url, { headers, method, body: JSON.stringify(body) })
|
||||||
@@ -273,15 +274,6 @@ export async function callback(params: {
|
|||||||
cookies,
|
cookies,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
return {
|
|
||||||
status: 401,
|
|
||||||
redirect: `${url}/error?error=${encodeURIComponent(
|
|
||||||
(e as Error).message
|
|
||||||
)}`,
|
|
||||||
cookies,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @type {import("src").Account} */
|
/** @type {import("src").Account} */
|
||||||
const account = {
|
const account = {
|
||||||
|
|||||||
@@ -21,11 +21,21 @@ const reset = "\x1b[0m"
|
|||||||
export const logger: LoggerInstance = {
|
export const logger: LoggerInstance = {
|
||||||
error(error: AuthError) {
|
error(error: AuthError) {
|
||||||
const url = `https://errors.authjs.dev#${error.name.toLowerCase()}`
|
const url = `https://errors.authjs.dev#${error.name.toLowerCase()}`
|
||||||
console.error(error.stack)
|
|
||||||
console.error(
|
console.error(
|
||||||
`${red}[auth][error][${error.name}]${reset}: Read more at ${url}`
|
`${red}[auth][error][${error.name}]${reset}:${
|
||||||
|
error.message ? ` ${error.message}.` : ""
|
||||||
|
} Read more at ${url}`
|
||||||
)
|
)
|
||||||
error.metadata && console.error(JSON.stringify(error.metadata, null, 2))
|
if (error.cause) {
|
||||||
|
const { err, ...data } = error.cause as any
|
||||||
|
console.error(`${red}[auth][cause]${reset}:`, (err as Error).stack)
|
||||||
|
console.error(
|
||||||
|
`${red}[auth][details]${reset}:`,
|
||||||
|
JSON.stringify(data, null, 2)
|
||||||
|
)
|
||||||
|
} else if (error.stack) {
|
||||||
|
console.error(error.stack.replace(/.*/, "").substring(1))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
warn(code) {
|
warn(code) {
|
||||||
const url = `https://errors.authjs.dev#${code}`
|
const url = `https://errors.authjs.dev#${code}`
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
* ## Usage
|
* ## Usage
|
||||||
*
|
*
|
||||||
* ```ts title="src/hooks.server.ts"
|
* ```ts title="src/hooks.server.ts"
|
||||||
* import SvelteKitAuth from "@auth/sveltekit"
|
* import { SvelteKitAuth } from "@auth/sveltekit"
|
||||||
* import GitHub from "@auth/core/providers/github"
|
* import GitHub from "@auth/core/providers/github"
|
||||||
* import { GITHUB_ID, GITHUB_SECRET } from "$env/static/private"
|
* import { GITHUB_ID, GITHUB_SECRET } from "$env/static/private"
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
"Balázs Orbán <info@balazsorban.com>",
|
"Balázs Orbán <info@balazsorban.com>",
|
||||||
"Nico Domino <yo@ndo.dev>",
|
"Nico Domino <yo@ndo.dev>",
|
||||||
"Lluis Agusti <hi@llu.lu>",
|
"Lluis Agusti <hi@llu.lu>",
|
||||||
"Thang Huu Vu <thvu@hey.com>"
|
"Thang Huu Vu <hi@thvu.dev>"
|
||||||
],
|
],
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"module": "index.js",
|
"module": "index.js",
|
||||||
|
|||||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@@ -258,6 +258,7 @@ importers:
|
|||||||
docusaurus-plugin-typedoc: ^0.18.0
|
docusaurus-plugin-typedoc: ^0.18.0
|
||||||
mdx-mermaid: 1.2.2
|
mdx-mermaid: 1.2.2
|
||||||
mermaid: 9.0.1
|
mermaid: 9.0.1
|
||||||
|
next-auth: workspace:*
|
||||||
prism-react-renderer: 1.3.5
|
prism-react-renderer: 1.3.5
|
||||||
react: ^18.2.0
|
react: ^18.2.0
|
||||||
react-dom: ^18.2.0
|
react-dom: ^18.2.0
|
||||||
@@ -272,6 +273,7 @@ importers:
|
|||||||
classnames: 2.3.2
|
classnames: 2.3.2
|
||||||
mdx-mermaid: 1.2.2_mermaid@9.0.1+react@18.2.0
|
mdx-mermaid: 1.2.2_mermaid@9.0.1+react@18.2.0
|
||||||
mermaid: 9.0.1
|
mermaid: 9.0.1
|
||||||
|
next-auth: link:../packages/next-auth
|
||||||
prism-react-renderer: 1.3.5_react@18.2.0
|
prism-react-renderer: 1.3.5_react@18.2.0
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-dom: 18.2.0_react@18.2.0
|
react-dom: 18.2.0_react@18.2.0
|
||||||
@@ -13604,7 +13606,7 @@ packages:
|
|||||||
/axios/0.21.4_debug@3.2.7:
|
/axios/0.21.4_debug@3.2.7:
|
||||||
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
|
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects: 1.15.1
|
follow-redirects: 1.15.1_debug@3.2.7
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- debug
|
- debug
|
||||||
dev: false
|
dev: false
|
||||||
@@ -19295,6 +19297,18 @@ packages:
|
|||||||
debug:
|
debug:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
/follow-redirects/1.15.1_debug@3.2.7:
|
||||||
|
resolution: {integrity: sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==}
|
||||||
|
engines: {node: '>=4.0'}
|
||||||
|
peerDependencies:
|
||||||
|
debug: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
debug:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
debug: 3.2.7
|
||||||
|
dev: false
|
||||||
|
|
||||||
/follow-redirects/1.15.1_debug@4.3.4:
|
/follow-redirects/1.15.1_debug@4.3.4:
|
||||||
resolution: {integrity: sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==}
|
resolution: {integrity: sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==}
|
||||||
engines: {node: '>=4.0'}
|
engines: {node: '>=4.0'}
|
||||||
|
|||||||
24
turbo.json
24
turbo.json
@@ -1,19 +1,25 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://turborepo.org/schema.json",
|
"$schema": "https://turborepo.org/schema.json",
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"docs#build": {
|
|
||||||
"dependsOn": [
|
|
||||||
"^build",
|
|
||||||
"next-auth#build",
|
|
||||||
"@auth/core#build",
|
|
||||||
"@auth/sveltekit#build"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"build": {
|
"build": {
|
||||||
"dependsOn": ["^build"]
|
"dependsOn": ["^build"]
|
||||||
},
|
},
|
||||||
"next-auth#build": {
|
"next-auth#build": {
|
||||||
"dependsOn": ["^build"]
|
"dependsOn": ["^build"],
|
||||||
|
"outputs": [
|
||||||
|
"client/**",
|
||||||
|
"core/**",
|
||||||
|
"css/**",
|
||||||
|
"jwt/**",
|
||||||
|
"next/**",
|
||||||
|
"providers/**",
|
||||||
|
"react/**",
|
||||||
|
"index.d.ts",
|
||||||
|
"index.js",
|
||||||
|
"adapters.d.ts",
|
||||||
|
"middleware.d.ts",
|
||||||
|
"middleware.js"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"clean": {
|
"clean": {
|
||||||
"cache": false
|
"cache": false
|
||||||
|
|||||||
Reference in New Issue
Block a user