Compare commits

..

3 Commits

Author SHA1 Message Date
Balázs Orbán
c8a201a247 Add missing installation requirements 2023-01-01 16:12:41 +01:00
Didi Keke
5586f07480 Add missing DynamoDBClientConfig interface import 2023-01-01 16:09:02 +01:00
Didi Keke
85ccd78977 Add @aws-sdk/client-dynamodb as peer dependency 2023-01-01 16:08:48 +01:00
13 changed files with 58 additions and 165 deletions

View File

@@ -9,7 +9,6 @@ module.exports = {
files: [
"apps/dev/pages/api/auth/[...nextauth].ts",
"docs/{sidebars,docusaurus.config}.js",
"packages/core/src/index.ts",
],
options: { printWidth: 150 },
},

View File

@@ -0,0 +1,8 @@
// This is an example of how to access a session from an API route
import { unstable_getServerSession } from "next-auth/next"
import { authOptions } from "../auth/[...nextauth]"
export default async (req, res) => {
const session = await unstable_getServerSession(req, res, authOptions)
res.json(session)
}

View File

@@ -1,21 +0,0 @@
import { Auth, SessionRequest } from "@auth/core"
import { authConfig } from "../auth/[...nextauth]"
export default async function handle(req: Request) {
authConfig.secret = process.env.AUTH_SECRET
const response = await Auth(new SessionRequest(req), authConfig)
const session = await response.session()
if (!session) {
return new Response("Not authenticated", { status: 401 })
}
console.log(session.user) // Do something with the session
// Pass the original headers to set cookies (eg.: updating the session expiry)
response.headers.set("content-type", "text/plain")
return new Response("Authenticated", { headers: response.headers })
}
export const config = {
runtime: "experimental-edge",
}

View File

@@ -22,7 +22,6 @@
"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",

View File

@@ -293,6 +293,6 @@ html[data-theme="dark"] #carbonads .carbon-poweredby {
See: https://github.com/TypeStrong/typedoc/issues/2006
*/
/* h3.anchor + p:has(code, strong), */ /** hack did not work as it hides property types elsewhere */
/* #classes {
#classes {
display: none;
} */
}

View File

@@ -5,7 +5,6 @@
"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",

View File

@@ -20,7 +20,7 @@
"Balázs Orbán <info@balazsorban.com>",
"Nico Domino <yo@ndo.dev>",
"Lluis Agusti <hi@llu.lu>",
"Thang Huu Vu <hi@thvu.dev>",
"Thang Huu Vu <thvu@hey.com>",
"Iain Collins <me@iaincollins.com"
],
"type": "module",

View File

@@ -40,17 +40,17 @@ import { logger, setLogger, type LoggerInstance } from "./lib/utils/logger.js"
import { toInternalRequest, toResponse } from "./lib/web.js"
import type { Adapter } from "./adapters.js"
import type { CallbacksOptions, CookiesOptions, EventCallbacks, PagesOptions, SessionOptions, Theme } from "./types.js"
import type {
CallbacksOptions,
CookiesOptions,
EventCallbacks,
PagesOptions,
SessionOptions,
Theme,
} from "./types.js"
import type { Provider } from "./providers/index.js"
import { JWTOptions } from "./jwt.js"
import { ProvidersRequest, ProvidersResponse, SessionRequest, SessionResponse } from "./lib/web-extension.js"
export * from "./lib/web-extension.js"
/** Returns a special {@link SessionResponse} instance to read the session from the request. */
export function Auth(request: SessionRequest, config: AuthConfig): Promise<SessionResponse>
/** Returns a special {@link ProvidersResponse} instance to read the list of providers in a client-safe way. */
export function Auth(request: ProvidersRequest, config: AuthConfig): Promise<ProvidersResponse>
/**
* Core functionality provided by Auth.js.
*
@@ -69,18 +69,19 @@ export function Auth(request: ProvidersRequest, config: AuthConfig): Promise<Pro
*```
* @see [Documentation](https://authjs.dev)
*/
export function Auth(request: Request, config: AuthConfig): Promise<Response>
export async function Auth(request: Request, config: AuthConfig): Promise<Response> {
export async function Auth(
request: Request,
config: AuthConfig
): Promise<Response> {
setLogger(config.logger, config.debug)
const isAuthRequest = request instanceof SessionRequest || request instanceof ProvidersRequest
if (isAuthRequest) config.trustHost = true
const internalRequest = await toInternalRequest(request)
if (internalRequest instanceof Error) {
logger.error(internalRequest)
return new Response(`Error: This action with HTTP ${request.method} is not supported.`, { status: 400 })
return new Response(
`Error: This action with HTTP ${request.method} is not supported.`,
{ status: 400 }
)
}
const assertionResult = assertConfig(internalRequest, config)
@@ -91,10 +92,14 @@ export async function Auth(request: Request, config: AuthConfig): Promise<Respon
// Bail out early if there's an error in the user config
logger.error(assertionResult)
const htmlPages = ["signin", "signout", "error", "verify-request"]
if (!htmlPages.includes(internalRequest.action) || internalRequest.method !== "GET") {
if (
!htmlPages.includes(internalRequest.action) ||
internalRequest.method !== "GET"
) {
return new Response(
JSON.stringify({
message: "There was a problem with the server configuration. Check the server logs for more information.",
message:
"There was a problem with the server configuration. Check the server logs for more information.",
code: assertionResult.name,
}),
{ status: 500, headers: { "Content-Type": "application/json" } }
@@ -103,11 +108,19 @@ export async function Auth(request: Request, config: AuthConfig): Promise<Respon
const { pages, theme } = config
const authOnErrorPage = pages?.error && internalRequest.url.searchParams.get("callbackUrl")?.startsWith(pages.error)
const authOnErrorPage =
pages?.error &&
internalRequest.url.searchParams
.get("callbackUrl")
?.startsWith(pages.error)
if (!pages?.error || authOnErrorPage) {
if (authOnErrorPage) {
logger.error(new ErrorPageLoop(`The error page ${pages?.error} should not require authentication`))
logger.error(
new ErrorPageLoop(
`The error page ${pages?.error} should not require authentication`
)
)
}
const render = renderPage({ theme })
const page = render.error({ error: "Configuration" })
@@ -131,18 +144,6 @@ export async function Auth(request: Request, config: AuthConfig): Promise<Respon
headers: response.headers,
})
}
if (isAuthRequest) {
switch (request.action) {
case "session":
return new SessionResponse(response.body, response)
case "providers":
return new ProvidersResponse(response.body, response)
default:
return response
}
}
return response
}

View File

@@ -1,95 +0,0 @@
import type { AuthAction, Session } from "../types.js"
import { PublicProvider } from "./routes/providers.js"
/** @internal */
export abstract class AuthRequest extends Request {
abstract action: AuthAction
}
/**
* Extends the standard {@link Request} to add a `session()` method on the response
* for retrieving the {@link Session} object.
*/
export class SessionRequest extends AuthRequest {
action = "session" as const
constructor(req: Request) {
super(req.url, req)
}
}
export class SessionResponse extends Response {
action = "session" as const
/**
* Returns the {@link Session} object from the response, or `null`
* if the session is unavailable (config error, not authenticated, etc.).
*
* @example
* ```ts
* export default async function handle(req: Request) {
* const response = await Auth(new SessionRequest(req), authConfig)
* const session = await response.session()
*
* if (!session) {
* return new Response("Not authenticated", { status: 401 })
* }
*
* console.log(session.user) // Do something with the session
* return response // or return whatever you want.
* }
* ```
*/
async session(): Promise<Session | null> {
try {
const data = await this.clone().json()
if (!this.ok || !data || !Object.keys(data).length) {
return null
}
return data
} catch {
return null
}
}
}
/**
* Extends the standard {@link Request} to add a `providers()` method on the response
* for retrieving a list of client-safe provider configuration. Useful for
* rendering a list of sign-in options.
*/
export class ProvidersRequest extends AuthRequest {
action = "providers" as const
constructor(req: Request) {
super(req.url, req)
}
}
export class ProvidersResponse extends Response {
action = "providers" as const
/**
* Returns the list of providers from the response, or `null`
* if the providers are unavailable (config error, etc.).
* @example
* ```ts
* export default async function handle(req: Request) {
* const response = await Auth(new ProvidersRequest(req), authConfig)
* const providers = await response.providers()
* if (!providers) {
* return new Response("Providers unavailable", { status: 500 })
*
*
* console.log(providers) // Do something with the providers
* return response // or return whatever you want.
* }
* ```
*/
async providers(): Promise<PublicProvider[]> {
try {
if (!this.ok) return []
return Object.values(await this.clone().json())
} catch {
return []
}
}
}

View File

@@ -2,7 +2,6 @@ import { parse as parseCookie, serialize } from "cookie"
import { AuthError, UnknownAction } from "../errors.js"
import type { AuthAction, RequestInternal, ResponseInternal } from "../types.js"
import { ProvidersRequest, SessionRequest } from "./web-extension.js"
async function getBody(req: Request): Promise<Record<string, any> | undefined> {
if (!("body" in req) || !req.body || req.method !== "POST") return
@@ -35,11 +34,8 @@ export async function toInternalRequest(
// see init.ts
const url = new URL(req.url.replace(/\/$/, ""))
const { pathname } = url
let action: AuthAction | undefined
if (req instanceof SessionRequest || req instanceof ProvidersRequest) {
action = req.action
} else action = actions.find((a) => pathname.includes(a))
const action = actions.find((a) => pathname.includes(a))
if (!action) {
throw new UnknownAction("Cannot detect action.")
}

View File

@@ -9,7 +9,7 @@
"Balázs Orbán <info@balazsorban.com>",
"Nico Domino <yo@ndo.dev>",
"Lluis Agusti <hi@llu.lu>",
"Thang Huu Vu <hi@thvu.dev>"
"Thang Huu Vu <thvu@hey.com>"
],
"main": "index.js",
"module": "index.js",

2
pnpm-lock.yaml generated
View File

@@ -258,7 +258,6 @@ 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
@@ -273,7 +272,6 @@ 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

View File

@@ -1,19 +1,28 @@
{
"$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": [
"client/**",
"core/**",
"lib/**",
"css/**",
"jwt/**",
"next/**",
"providers/**",
"react/**",
"next/**",
"client/**",
"providers/**",
"core/**",
"index.d.ts",
"index.js",
"adapters.d.ts",