Compare commits
21 Commits
OrJDev/mai
...
feat/auth-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
471471b303 | ||
|
|
fd80f10625 | ||
|
|
cb2da4dd9c | ||
|
|
5064f20e61 | ||
|
|
5a6f76bf2c | ||
|
|
15bed6260c | ||
|
|
1423733d61 | ||
|
|
77d8f47f51 | ||
|
|
3120d28299 | ||
|
|
e6a320bb0f | ||
|
|
7d4d436efe | ||
|
|
c6f5c4d1cf | ||
|
|
09a075cc7e | ||
|
|
f1475955ea | ||
|
|
e6f48775fa | ||
|
|
ba87e86d47 | ||
|
|
b0dd1fac93 | ||
|
|
054288316b | ||
|
|
5e02019a3c | ||
|
|
9da0e66193 | ||
|
|
287c8f0f91 |
15
.github/sync.yml
vendored
@@ -7,12 +7,15 @@ nextauthjs/sveltekit-auth-example:
|
||||
- .github/FUNDING.yml
|
||||
- LICENSE
|
||||
|
||||
nextauthjs/solid-start-auth-example:
|
||||
- source: apps/example-solid-start
|
||||
dest: .
|
||||
deleteOrphaned: true
|
||||
- .github/FUNDING.yml
|
||||
- LICENSE
|
||||
# FIXME: Should re-enable, but currently fails:
|
||||
# https://github.com/nextauthjs/next-auth/actions/runs/3811709391/jobs/6484533340
|
||||
# (issue seems to be the name of the target repo)
|
||||
# nextauthjs/solid-start-auth-example:
|
||||
# - source: "apps/examples/solid-start"
|
||||
# dest: .
|
||||
# deleteOrphaned: true
|
||||
# - .github/FUNDING.yml
|
||||
# - LICENSE
|
||||
|
||||
nextauthjs/next-auth-gatsby-example:
|
||||
- source: apps/playgrounds/gatsby
|
||||
|
||||
@@ -9,6 +9,7 @@ module.exports = {
|
||||
files: [
|
||||
"apps/dev/pages/api/auth/[...nextauth].ts",
|
||||
"docs/{sidebars,docusaurus.config}.js",
|
||||
"packages/core/src/index.ts",
|
||||
],
|
||||
options: { printWidth: 150 },
|
||||
},
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
// 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)
|
||||
}
|
||||
21
apps/dev/nextjs/pages/api/examples/session.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
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",
|
||||
}
|
||||
8711
apps/example-solid-start/package-lock.json
generated
|
Before Width: | Height: | Size: 664 B After Width: | Height: | Size: 664 B |
@@ -29,7 +29,7 @@ const Home: ParentComponent = () => {
|
||||
</A>{" "}
|
||||
with{" "}
|
||||
<A
|
||||
href="https://authjs.dev/reference/solid-start/modules/main"
|
||||
href="https://authjs.dev/reference/solidstart"
|
||||
class="text-blue-500 underline font-bold"
|
||||
>
|
||||
SolidStart Auth
|
||||
@@ -3,7 +3,7 @@ id: 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.
|
||||
|
||||
@@ -11,10 +11,10 @@ You can find the full schema in the table structure section below.
|
||||
|
||||
## 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
|
||||
npm install next-auth @next-auth/dynamodb-adapter
|
||||
```bash npm2yarn2pnpm
|
||||
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.
|
||||
@@ -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.
|
||||
|
||||
```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 NextAuth from "next-auth";
|
||||
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.
|
||||
- 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)
|
||||
|
||||
@@ -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
|
||||
NextAuthTable:
|
||||
|
||||
@@ -46,7 +46,7 @@ const docusaurusConfig = {
|
||||
title: "Auth.js",
|
||||
logo: {
|
||||
alt: "Auth.js Logo",
|
||||
src: "img/logo/logo-xs.png",
|
||||
src: "img/logo/logo-xs.webp",
|
||||
},
|
||||
items: [
|
||||
{
|
||||
@@ -101,7 +101,7 @@ const docusaurusConfig = {
|
||||
announcementBar: {
|
||||
id: "new-major-announcement",
|
||||
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",
|
||||
textColor: "#fff",
|
||||
},
|
||||
@@ -121,6 +121,7 @@ const docusaurusConfig = {
|
||||
alt="Powered by Vercel"
|
||||
style="margin-top: 8px"
|
||||
height="32"
|
||||
width="167"
|
||||
src="https://raw.githubusercontent.com/nextauthjs/next-auth/main/docs/static/img/powered-by-vercel.svg"
|
||||
/>
|
||||
</a>`,
|
||||
@@ -181,7 +182,10 @@ const docusaurusConfig = {
|
||||
lastVersion: "current",
|
||||
showLastUpdateAuthor: true,
|
||||
showLastUpdateTime: true,
|
||||
remarkPlugins: [require("@sapphire/docusaurus-plugin-npm2yarn2pnpm").npm2yarn2pnpm, require("remark-github")],
|
||||
remarkPlugins: [
|
||||
require("@sapphire/docusaurus-plugin-npm2yarn2pnpm").npm2yarn2pnpm,
|
||||
require("remark-github"),
|
||||
],
|
||||
versions: {
|
||||
current: {
|
||||
label: "experimental",
|
||||
@@ -201,7 +205,15 @@ const docusaurusConfig = {
|
||||
...typedocConfig,
|
||||
id: "core",
|
||||
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",
|
||||
out: "reference/03-core",
|
||||
watch: process.env.TYPEDOC_WATCH,
|
||||
@@ -214,7 +226,9 @@ const docusaurusConfig = {
|
||||
...typedocConfig,
|
||||
id: "sveltekit",
|
||||
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",
|
||||
out: "reference/04-sveltekit",
|
||||
watch: process.env.TYPEDOC_WATCH,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -60,7 +60,7 @@ module.exports = {
|
||||
type: "doc",
|
||||
id: "reference/solidstart/index",
|
||||
},
|
||||
items: ["reference/solidstart/client"],
|
||||
items: ["reference/solidstart/client", "reference/solidstart/protected"],
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
|
||||
@@ -140,19 +140,19 @@ html[data-theme="dark"] hr {
|
||||
border-radius: 10rem;
|
||||
overflow: visible;
|
||||
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-origin: center;
|
||||
}
|
||||
|
||||
.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-origin: center;
|
||||
}
|
||||
|
||||
.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-origin: center;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
} */
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
margin-right: 1rem !important;
|
||||
}
|
||||
|
||||
.navbar__logo {
|
||||
width: 29px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.navbar__title {
|
||||
font-size: 1.2rem;
|
||||
margin-left: 0.2rem;
|
||||
|
||||
@@ -117,9 +117,11 @@ export default function Home() {
|
||||
<div className="container">
|
||||
<div className="hero-inner">
|
||||
<img
|
||||
src="/img/logo/logo-sm.png"
|
||||
src="/img/logo/logo-sm.webp"
|
||||
alt="Shield with key icon"
|
||||
className={styles.heroLogo}
|
||||
height="142"
|
||||
width="128"
|
||||
/>
|
||||
<div className={styles.heroText}>
|
||||
<h1 className="hero__title">{siteConfig.title}</h1>
|
||||
@@ -214,9 +216,9 @@ export default function Home() {
|
||||
<div className="row">
|
||||
<div className="col col--6">
|
||||
<div className="code">
|
||||
<h4 className="code-heading">
|
||||
<div className="code-heading">
|
||||
Next.js <span>/pages/api/auth/[...nextauth].ts</span>
|
||||
</h4>
|
||||
</div>
|
||||
<CodeBlock className="prism-code language-js">
|
||||
{nextJsCode}
|
||||
</CodeBlock>
|
||||
@@ -224,9 +226,9 @@ export default function Home() {
|
||||
</div>
|
||||
<div className="col col--6">
|
||||
<div className="code">
|
||||
<h4 className="code-heading">
|
||||
<div className="code-heading">
|
||||
SvelteKit <span>/hooks.server.ts</span>
|
||||
</h4>
|
||||
</div>
|
||||
<CodeBlock className="prism-code language-js">
|
||||
{svelteKitCode}
|
||||
</CodeBlock>
|
||||
@@ -234,9 +236,9 @@ export default function Home() {
|
||||
</div>
|
||||
<div className="col col--6">
|
||||
<div className="code">
|
||||
<h4 className="code-heading">
|
||||
<div className="code-heading">
|
||||
SolidStart <span>/routes/api/auth/[...solidauth].ts</span>
|
||||
</h4>
|
||||
</div>
|
||||
<CodeBlock className="prism-code language-js">
|
||||
{solidStartCode}
|
||||
</CodeBlock>
|
||||
|
||||
BIN
docs/static/img/logo/logo-sm.webp
vendored
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
docs/static/img/logo/logo-xs.webp
vendored
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
docs/static/img/logo/logo.webp
vendored
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
docs/static/img/mesh-1.webp
vendored
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
docs/static/img/mesh-2.webp
vendored
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/static/img/mesh-3.webp
vendored
Normal file
|
After Width: | Height: | Size: 36 KiB |
@@ -60,6 +60,11 @@
|
||||
"destination": "https://github.com/nextauthjs/next-auth/discussions/categories/questions",
|
||||
"permanent": true
|
||||
},
|
||||
{
|
||||
"source": "/reference/solid-start/:path*",
|
||||
"destination": "/reference/solidstart/:path*",
|
||||
"permanent": true
|
||||
},
|
||||
{
|
||||
"source": "/",
|
||||
"has": [
|
||||
@@ -70,6 +75,16 @@
|
||||
],
|
||||
"destination": "https://authjs.dev/reference/sveltekit/modules/main"
|
||||
},
|
||||
{
|
||||
"source": "/",
|
||||
"has": [
|
||||
{
|
||||
"type": "host",
|
||||
"value": "solid-start.authjs.dev"
|
||||
}
|
||||
],
|
||||
"destination": "https://authjs.dev/reference/solid-start"
|
||||
},
|
||||
{
|
||||
"source": "/:path(.*)",
|
||||
"has": [
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
"author": "Pol Marnette",
|
||||
"license": "ISC",
|
||||
"peerDependencies": {
|
||||
"@aws-sdk/client-dynamodb": "^3.36.1",
|
||||
"@aws-sdk/lib-dynamodb": "^3.36.1",
|
||||
"next-auth": "^4"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@auth/core",
|
||||
"version": "0.2.3",
|
||||
"version": "0.2.4",
|
||||
"description": "Authentication for the Web.",
|
||||
"keywords": [
|
||||
"authentication",
|
||||
@@ -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",
|
||||
@@ -61,10 +61,10 @@
|
||||
},
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@panva/hkdf": "1.0.2",
|
||||
"@panva/hkdf": "^1.0.2",
|
||||
"cookie": "0.5.0",
|
||||
"jose": "4.11.1",
|
||||
"oauth4webapi": "2.0.6",
|
||||
"jose": "^4.11.1",
|
||||
"oauth4webapi": "^2.0.6",
|
||||
"preact": "10.11.3",
|
||||
"preact-render-to-string": "5.2.3"
|
||||
},
|
||||
@@ -92,4 +92,4 @@
|
||||
"postcss": "8.4.19",
|
||||
"postcss-nested": "6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,19 +69,18 @@ import { JWTOptions } from "./jwt.js"
|
||||
*```
|
||||
* @see [Documentation](https://authjs.dev)
|
||||
*/
|
||||
export async function Auth(
|
||||
request: Request,
|
||||
config: AuthConfig
|
||||
): Promise<Response> {
|
||||
export 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)
|
||||
@@ -92,14 +91,10 @@ export async function Auth(
|
||||
// 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" } }
|
||||
@@ -108,19 +103,11 @@ export async function Auth(
|
||||
|
||||
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" })
|
||||
@@ -144,6 +131,18 @@ export async function Auth(
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
95
packages/core/src/lib/web-extension.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
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 []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ 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
|
||||
@@ -34,8 +35,11 @@ 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.")
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@auth/solid-start",
|
||||
"description": "Authentication for SolidStart.",
|
||||
"version": "0.0.1",
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"client.*",
|
||||
@@ -55,4 +55,4 @@
|
||||
"author": "OrJDev <orjdeveloper@gmail.com>",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"license": "ISC"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@auth/sveltekit",
|
||||
"version": "0.1.10",
|
||||
"version": "0.1.11",
|
||||
"description": "Authentication for SvelteKit.",
|
||||
"keywords": [
|
||||
"authentication",
|
||||
@@ -69,4 +69,4 @@
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
22
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
|
||||
@@ -577,15 +579,15 @@ importers:
|
||||
packages/core:
|
||||
specifiers:
|
||||
'@next-auth/tsconfig': workspace:*
|
||||
'@panva/hkdf': 1.0.2
|
||||
'@panva/hkdf': ^1.0.2
|
||||
'@types/cookie': 0.5.1
|
||||
'@types/node': 18.11.10
|
||||
'@types/nodemailer': 6.4.6
|
||||
'@types/react': 18.0.26
|
||||
autoprefixer: 10.4.13
|
||||
cookie: 0.5.0
|
||||
jose: 4.11.1
|
||||
oauth4webapi: 2.0.6
|
||||
jose: ^4.11.1
|
||||
oauth4webapi: ^2.0.6
|
||||
postcss: 8.4.19
|
||||
postcss-nested: 6.0.0
|
||||
preact: 10.11.3
|
||||
@@ -13093,10 +13095,8 @@ packages:
|
||||
indent-string: 4.0.0
|
||||
dev: true
|
||||
|
||||
/ajv-formats/2.1.1_ajv@8.11.0:
|
||||
/ajv-formats/2.1.1:
|
||||
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
|
||||
peerDependencies:
|
||||
ajv: ^8.0.0
|
||||
peerDependenciesMeta:
|
||||
ajv:
|
||||
optional: true
|
||||
@@ -13630,7 +13630,7 @@ packages:
|
||||
/axios/0.25.0_debug@4.3.4:
|
||||
resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.1_debug@4.3.4
|
||||
follow-redirects: 1.15.1
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
|
||||
@@ -18690,7 +18690,7 @@ packages:
|
||||
dependencies:
|
||||
'@apidevtools/json-schema-ref-parser': 9.0.9
|
||||
ajv: 8.11.0
|
||||
ajv-formats: 2.1.1_ajv@8.11.0
|
||||
ajv-formats: 2.1.1
|
||||
body-parser: 1.20.0
|
||||
content-type: 1.0.4
|
||||
deep-freeze: 0.0.1
|
||||
@@ -19296,7 +19296,6 @@ packages:
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
dev: true
|
||||
|
||||
/follow-redirects/1.15.1_debug@3.2.7:
|
||||
resolution: {integrity: sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==}
|
||||
@@ -19320,6 +19319,7 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
dev: true
|
||||
|
||||
/for-each/0.3.3:
|
||||
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
||||
@@ -21106,7 +21106,7 @@ packages:
|
||||
engines: {node: '>=8.0.0'}
|
||||
dependencies:
|
||||
eventemitter3: 4.0.7
|
||||
follow-redirects: 1.15.1_debug@4.3.4
|
||||
follow-redirects: 1.15.1
|
||||
requires-port: 1.0.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
@@ -29489,7 +29489,7 @@ packages:
|
||||
dependencies:
|
||||
'@types/json-schema': 7.0.11
|
||||
ajv: 8.11.0
|
||||
ajv-formats: 2.1.1_ajv@8.11.0
|
||||
ajv-formats: 2.1.1
|
||||
ajv-keywords: 5.1.0_ajv@8.11.0
|
||||
dev: true
|
||||
|
||||
|
||||
19
turbo.json
@@ -1,14 +1,25 @@
|
||||
{
|
||||
"$schema": "https://turborepo.org/schema.json",
|
||||
"pipeline": {
|
||||
"docs#build": {
|
||||
"dependsOn": ["^build", "next-auth#build"]
|
||||
},
|
||||
"build": {
|
||||
"dependsOn": ["^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": {
|
||||
"cache": false
|
||||
|
||||