mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
8 Commits
fix/dynamo
...
fix/improv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f42ef7cc62 | ||
|
|
35a708a2c3 | ||
|
|
4f919ca76f | ||
|
|
036e34b4b6 | ||
|
|
d2288ee4cc | ||
|
|
5a6f76bf2c | ||
|
|
15bed6260c | ||
|
|
1423733d61 |
@@ -22,6 +22,7 @@
|
||||
"classnames": "^2.3.2",
|
||||
"mdx-mermaid": "1.2.2",
|
||||
"mermaid": "9.0.1",
|
||||
"next-auth": "workspace:*",
|
||||
"prism-react-renderer": "1.3.5",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"repository": "https://github.com/nextauthjs/next-auth.git",
|
||||
"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",
|
||||
"test": "turbo run test --concurrency=1 --filter=[HEAD^1] --filter=./packages/* --filter=!*pouchdb-* --filter=!@*upstash* --filter=!*dynamodb-*",
|
||||
"clean": "turbo run clean --no-cache",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"Balázs Orbán <info@balazsorban.com>",
|
||||
"Nico Domino <yo@ndo.dev>",
|
||||
"Lluis Agusti <hi@llu.lu>",
|
||||
"Thang Huu Vu <thvu@hey.com>",
|
||||
"Thang Huu Vu <hi@thvu.dev>",
|
||||
"Iain Collins <me@iaincollins.com"
|
||||
],
|
||||
"type": "module",
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
interface ErrorCause extends Record<string, unknown> {}
|
||||
|
||||
/** @internal */
|
||||
export class AuthError extends Error {
|
||||
metadata?: Record<string, unknown>
|
||||
constructor(message: Error | string, metadata?: Record<string, unknown>) {
|
||||
constructor(message: string | Error | ErrorCause, cause?: ErrorCause) {
|
||||
if (message instanceof Error) {
|
||||
super(message.message)
|
||||
this.stack = message.stack
|
||||
} else super(message)
|
||||
this.name = this.constructor.name
|
||||
this.metadata = metadata
|
||||
super(undefined, {
|
||||
cause: { err: message, ...(message.cause as any), ...cause },
|
||||
})
|
||||
} else if (typeof message === "string") {
|
||||
if (cause instanceof Error) {
|
||||
cause = { err: cause, ...(cause.cause as any) }
|
||||
}
|
||||
super(message, cause)
|
||||
} else {
|
||||
super(undefined, message)
|
||||
}
|
||||
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 */
|
||||
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 {}
|
||||
|
||||
/** @todo */
|
||||
@@ -93,3 +140,10 @@ export class UnsupportedStrategy extends AuthError {}
|
||||
|
||||
/** @todo */
|
||||
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
|
||||
// and need to return an error.
|
||||
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
|
||||
@@ -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
|
||||
// to sign in via email to verify their identity and then link the accounts.
|
||||
throw new AccountNotLinked(
|
||||
"Another account already exists with the same e-mail address"
|
||||
"Another account already exists with the same e-mail address",
|
||||
{ provider: account.provider }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { handleLogin } from "../callback-handler.js"
|
||||
import { CallbackRouteError } from "../../errors.js"
|
||||
import { CallbackRouteError, Verification } from "../../errors.js"
|
||||
import { handleOAuth } from "../oauth/callback.js"
|
||||
import { createHash } from "../web.js"
|
||||
import { handleAuthorized } from "./shared.js"
|
||||
@@ -8,7 +8,6 @@ import type { AdapterSession } from "../../adapters.js"
|
||||
import type {
|
||||
RequestInternal,
|
||||
ResponseInternal,
|
||||
User,
|
||||
InternalOptions,
|
||||
} from "../../types.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 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) {
|
||||
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
|
||||
@@ -166,10 +169,10 @@ export async function callback(params: {
|
||||
token: await createHash(`${token}${secret}`),
|
||||
})
|
||||
|
||||
const invalidInvite = !invite || invite.expires.valueOf() < Date.now()
|
||||
if (invalidInvite) {
|
||||
return { redirect: `${url}/error?error=Verification`, cookies }
|
||||
}
|
||||
const hasInvite = !!invite
|
||||
const expired = invite ? invite.expires.valueOf() < Date.now() : undefined
|
||||
const invalidInvite = !hasInvite || expired
|
||||
if (invalidInvite) throw new Verification({ hasInvite, expired })
|
||||
|
||||
// @ts-expect-error -- Verified in `assertConfig`.
|
||||
const profile = await getAdapterUserFromEmail(identifier, adapter)
|
||||
@@ -252,33 +255,22 @@ export async function callback(params: {
|
||||
} else if (provider.type === "credentials" && method === "POST") {
|
||||
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
|
||||
Object.entries(query ?? {}).forEach(([k, v]) =>
|
||||
url.searchParams.set(k, v)
|
||||
)
|
||||
const user = await provider.authorize(
|
||||
credentials,
|
||||
// prettier-ignore
|
||||
Object.entries(query ?? {}).forEach(([k, v]) => url.searchParams.set(k, v))
|
||||
user = await provider.authorize(
|
||||
credentials,
|
||||
// prettier-ignore
|
||||
new Request(url, { headers, method, body: JSON.stringify(body) })
|
||||
)
|
||||
if (!user) {
|
||||
return {
|
||||
status: 401,
|
||||
redirect: `${url}/error?${new URLSearchParams({
|
||||
error: "CredentialsSignin",
|
||||
provider: provider.id,
|
||||
})}`,
|
||||
cookies,
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
new Request(url, { headers, method, body: JSON.stringify(body) })
|
||||
)
|
||||
if (!user) {
|
||||
return {
|
||||
status: 401,
|
||||
redirect: `${url}/error?error=${encodeURIComponent(
|
||||
(e as Error).message
|
||||
)}`,
|
||||
redirect: `${url}/error?${new URLSearchParams({
|
||||
error: "CredentialsSignin",
|
||||
provider: provider.id,
|
||||
})}`,
|
||||
cookies,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,21 @@ const reset = "\x1b[0m"
|
||||
export const logger: LoggerInstance = {
|
||||
error(error: AuthError) {
|
||||
const url = `https://errors.authjs.dev#${error.name.toLowerCase()}`
|
||||
console.error(error.stack)
|
||||
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) {
|
||||
const url = `https://errors.authjs.dev#${code}`
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* ## Usage
|
||||
*
|
||||
* ```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_ID, GITHUB_SECRET } from "$env/static/private"
|
||||
*
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"Balázs Orbán <info@balazsorban.com>",
|
||||
"Nico Domino <yo@ndo.dev>",
|
||||
"Lluis Agusti <hi@llu.lu>",
|
||||
"Thang Huu Vu <thvu@hey.com>"
|
||||
"Thang Huu Vu <hi@thvu.dev>"
|
||||
],
|
||||
"main": "index.js",
|
||||
"module": "index.js",
|
||||
|
||||
2
pnpm-lock.yaml
generated
2
pnpm-lock.yaml
generated
@@ -258,6 +258,7 @@ importers:
|
||||
docusaurus-plugin-typedoc: ^0.18.0
|
||||
mdx-mermaid: 1.2.2
|
||||
mermaid: 9.0.1
|
||||
next-auth: workspace:*
|
||||
prism-react-renderer: 1.3.5
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
@@ -272,6 +273,7 @@ importers:
|
||||
classnames: 2.3.2
|
||||
mdx-mermaid: 1.2.2_mermaid@9.0.1+react@18.2.0
|
||||
mermaid: 9.0.1
|
||||
next-auth: link:../packages/next-auth
|
||||
prism-react-renderer: 1.3.5_react@18.2.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
|
||||
15
turbo.json
15
turbo.json
@@ -1,28 +1,19 @@
|
||||
{
|
||||
"$schema": "https://turborepo.org/schema.json",
|
||||
"pipeline": {
|
||||
"docs#build": {
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
"next-auth#build",
|
||||
"@auth/core#build",
|
||||
"@auth/sveltekit#build"
|
||||
]
|
||||
},
|
||||
"build": {
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"next-auth#build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": [
|
||||
"lib/**",
|
||||
"client/**",
|
||||
"core/**",
|
||||
"css/**",
|
||||
"jwt/**",
|
||||
"react/**",
|
||||
"next/**",
|
||||
"client/**",
|
||||
"providers/**",
|
||||
"core/**",
|
||||
"react/**",
|
||||
"index.d.ts",
|
||||
"index.js",
|
||||
"adapters.d.ts",
|
||||
|
||||
Reference in New Issue
Block a user