Compare commits

..

1 Commits

Author SHA1 Message Date
Balázs Orbán
c0c3a97961 feat: make generateSessionToken awaitable 2023-01-28 13:16:55 +01:00
28 changed files with 172 additions and 177 deletions

View File

@@ -1,6 +1,6 @@
import { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
export default async function Page() {
const session = await getServerSession()
const session = await unstable_getServerSession()
return <pre>{JSON.stringify(session, null, 2)}</pre>
}

View File

@@ -1,9 +1,9 @@
// This is an example of to protect an API route
import { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
import { authOptions } from "../auth/[...nextauth]"
export default async (req, res) => {
const session = await getServerSession(req, res, authOptions)
const session = await unstable_getServerSession(req, res, authOptions)
if (session) {
res.send({

View File

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

View File

@@ -1,11 +1,11 @@
// This is an example of how to query data from Supabase with RLS.
// Learn more about Row Levele Security (RLS): https://supabase.com/docs/guides/auth/row-level-security
import { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
import { authOptions } from "../auth/[...nextauth]"
import { createClient } from "@supabase/supabase-js"
export default async (req, res) => {
const session = await getServerSession(req, res, authOptions)
const session = await unstable_getServerSession(req, res, authOptions)
if (!session)
return res.send(JSON.stringify({ error: "No session!" }, null, 2))

View File

@@ -1,5 +1,5 @@
// This is an example of how to protect content using server rendering
import { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
import { authOptions } from "./api/auth/[...nextauth]"
import Layout from "../components/layout"
import AccessDenied from "../components/access-denied"
@@ -26,7 +26,11 @@ export default function Page({ content, session }) {
}
export async function getServerSideProps(context) {
const session = await getServerSession(context.req, context.res, authOptions)
const session = await unstable_getServerSession(
context.req,
context.res,
authOptions
)
let content = null
if (session) {

View File

@@ -1,6 +1,6 @@
import { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
import Layout from "../components/layout"
import { authOptions } from "./api/auth/[...nextauth]"
import { authOptions } from './api/auth/[...nextauth]';
export default function Page() {
// As this page uses Server Side Rendering, the `session` will be already
@@ -12,11 +12,11 @@ export default function Page() {
<Layout>
<h1>Server Side Rendering</h1>
<p>
This page uses the <strong>getServerSession()</strong> method in{" "}
<strong>getServerSideProps()</strong>.
This page uses the <strong>unstable_getServerSession()</strong> method
in <strong>getServerSideProps()</strong>.
</p>
<p>
Using <strong>getServerSession()</strong> in{" "}
Using <strong>unstable_getServerSession()</strong> in{" "}
<strong>getServerSideProps()</strong> is currently the recommended
approach, although the API may still change, if you need to support
Server Side Rendering with authentication.
@@ -40,7 +40,11 @@ export default function Page() {
export async function getServerSideProps(context) {
return {
props: {
session: await getServerSession(context.req, context.res, authOptions),
session: await unstable_getServerSession(
context.req,
context.res,
authOptions
),
},
}
}

View File

@@ -1,6 +1,6 @@
// This is an example of how to protect content using server rendering
// and fetching data from Supabase with RLS enabled.
import { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
import { authOptions } from "./api/auth/[...nextauth]"
import { createClient } from "@supabase/supabase-js"
import Layout from "../components/layout"
@@ -27,7 +27,11 @@ export default function Page({ data, session }) {
}
export async function getServerSideProps(context) {
const session = await getServerSession(context.req, context.res, authOptions)
const session = await unstable_getServerSession(
context.req,
context.res,
authOptions
)
if (!session)
return {

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
import { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
import { authOptions } from "./api/auth/[...nextauth]"
import Layout from "../components/layout"
@@ -12,11 +12,11 @@ export default function ServerSidePage({ session }: { session: Session }) {
<Layout>
<h1>Server Side Rendering</h1>
<p>
This page uses the <strong>getServerSession()</strong> method in{" "}
<strong>getServerSideProps()</strong>.
This page uses the <strong>unstable_getServerSession()</strong> method
in <strong>getServerSideProps()</strong>.
</p>
<p>
Using <strong>getServerSession()</strong> in{" "}
Using <strong>unstable_getServerSession()</strong> in{" "}
<strong>getServerSideProps()</strong> is the recommended approach if you
need to support Server Side Rendering with authentication.
</p>
@@ -37,7 +37,11 @@ export default function ServerSidePage({ session }: { session: Session }) {
export async function getServerSideProps(context: GetServerSidePropsContext) {
return {
props: {
session: await getServerSession(context.req, context.res, authOptions),
session: await unstable_getServerSession(
context.req,
context.res,
authOptions
),
},
}
}

View File

@@ -254,7 +254,7 @@ The `supabaseAccessToken` is now available on the `session` object and can be pa
```js
// ...
// Use `useSession()` or `getServerSession()` to get the NextAuth session.
// Use `useSession()` or `unstable_getServerSession()` to get the NextAuth session.
const { supabaseAccessToken } = session

View File

@@ -107,7 +107,7 @@ The redirect callback may be invoked more than once in the same flow.
This callback is called whenever a JSON Web Token is created (i.e. at sign
in) or updated (i.e whenever a session is accessed in the client). The returned value will be [encrypted](/configuration/options#jwt), and it is stored in a cookie.
Requests to `/api/auth/signin`, `/api/auth/session` and calls to `getSession()`, `getServerSession()`, `useSession()` will invoke this function, but only if you are using a [JWT session](/configuration/options#session). This method is not invoked when you persist sessions in a database.
Requests to `/api/auth/signin`, `/api/auth/session` and calls to `getSession()`, `unstable_getServerSession()`, `useSession()` will invoke this function, but only if you are using a [JWT session](/configuration/options#session). This method is not invoked when you persist sessions in a database.
- As with database persisted session expiry times, token expiry time is extended whenever a session is active.
- The arguments _user_, _account_, _profile_ and _isNewUser_ are only passed the first time this callback is called on a new session, after the user signs in. In subsequent calls, only `token` will be available.

View File

@@ -2,15 +2,15 @@
## `unstable_getServerSession`
This method was renamed to `getServerSession`. See the documentation below.
:::warning
This feature is experimental and may be removed or changed in the future.
:::
## `getServerSession`
When calling from server-side i.e. in API routes or in `getServerSideProps`, we recommend using this function instead of `getSession` to retrieve the `session` object. This method is especially useful when you are using NextAuth.js with a database. This method can _drastically_ reduce response time when used over `getSession` server-side, due to avoiding an extra `fetch` to an API Route (this is generally [not recommended in Next.js](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props#getserversideprops-or-api-routes)). In addition, `getServerSession` will correctly update the cookie expiry time and update the session content if `callbacks.jwt` or `callbacks.session` changed something.
When calling from server-side i.e. in API routes or in `getServerSideProps`, we recommend using this function instead of `getSession` to retrieve the `session` object. This method is especially useful when you are using NextAuth.js with a database. This method can _drastically_ reduce response time when used over `getSession` server-side, due to avoiding an extra `fetch` to an API Route (this is generally [not recommended in Next.js](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props#getserversideprops-or-api-routes)). In addition, `unstable_getServerSession` will correctly update the cookie expiry time and update the session content if `callbacks.jwt` or `callbacks.session` changed something.
Otherwise, if you only want to get the session token, see [`getToken`](/tutorials/securing-pages-and-api-routes#using-gettoken).
`getServerSession` requires passing the same object you would pass to `NextAuth` when initializing NextAuth.js. To do so, you can export your NextAuth.js options in the following way:
`unstable_getServerSession` requires passing the same object you would pass to `NextAuth` when initializing NextAuth.js. To do so, you can export your NextAuth.js options in the following way:
In `[...nextauth].ts`:
```ts
@@ -27,10 +27,10 @@ export default NextAuth(authOptions);
### In `getServerSideProps`:
```js
import { authOptions } from 'pages/api/auth/[...nextauth]'
import { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
export async function getServerSideProps(context) {
const session = await getServerSession(context.req, context.res, authOptions)
const session = await unstable_getServerSession(context.req, context.res, authOptions)
if (!session) {
return {
@@ -52,11 +52,11 @@ export async function getServerSideProps(context) {
### In API Routes:
```js
import { authOptions } from 'pages/api/auth/[...nextauth]'
import { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
export async function handler(req, res) {
const session = await getServerSession(req, res, authOptions)
const session = await unstable_getServerSession(req, res, authOptions)
if (!session) {
res.status(401).json({ message: "You must be logged in." });
@@ -71,14 +71,14 @@ export async function handler(req, res) {
### In `app/` directory:
You can also use `getServerSession` in Next.js' server components:
You can also use `unstable_getServerSession` in Next.js' server components:
```tsx
import { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
import { authOptions } from "pages/api/auth/[...nextauth]"
export default async function Page() {
const session = await getServerSession(authOptions)
const session = await unstable_getServerSession(authOptions)
return <pre>{JSON.stringify(session, null, 2)}</pre>
}
```

View File

@@ -157,11 +157,15 @@ You can create your own session management solution using data fetching librarie
## getSession()
- Client Side: **Yes**
- Server Side: **No** (See: [`getServerSession()`](/configuration/nextjs#unstable_getserversession)
- Server Side: **No** (See: [`unstable_getServerSession()`](/configuration/nextjs#unstable_getserversession)
NextAuth.js provides a `getSession()` helper which should be called **client side only** to return the current active session.
On the server side, **this is still available to use**, however, we recommend using `getServerSession` going forward. The idea behind this is to avoid an additional unnecessary `fetch` call on the server side. For more information, please check out [this issue](https://github.com/nextauthjs/next-auth/issues/1535).
On the server side, **this is still available to use**, however, we recommend using `unstable_getServerSession` going forward. The idea behind this is to avoid an additional unnecessary `fetch` call on the server side. For more information, please check out [this issue](https://github.com/nextauthjs/next-auth/issues/1535).
:::note
The `unstable_getServerSession` only has the prefix `unstable_` at the moment, because the API may change in the future. There are no known bugs at the moment and it is safe to use. If you discover any issues, please do report them as a [GitHub Issue](https://github.com/nextauthjs/next-auth/issues) and we will patch them as soon as possible.
:::
This helper is helpful in case you want to read the session outside of the context of React.
@@ -174,7 +178,7 @@ async function myFunction() {
}
```
Read the tutorial [securing pages and API routes](/tutorials/securing-pages-and-api-routes) to know how to fetch the session in server side calls using `getServerSession()`.
Read the tutorial [securing pages and API routes](/tutorials/securing-pages-and-api-routes) to know how to fetch the session in server side calls using `unstable_getServerSession()`.
---
@@ -418,7 +422,7 @@ If you pass the `session` page prop to the `<SessionProvider>` as in the exa
This only works on pages where you provide the correct `pageProps`, however. This is normally done in `getInitialProps` or `getServerSideProps` on an individual page basis like so:
```js title="pages/index.js"
import { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
import { authOptions } from './api/auth/[...nextauth]'
...
@@ -426,7 +430,7 @@ import { authOptions } from './api/auth/[...nextauth]'
export async function getServerSideProps({ req, res }) {
return {
props: {
session: await getServerSession(req, res, authOptions)
session: await unstable_getServerSession(req, res, authOptions)
}
}
}

View File

@@ -106,14 +106,14 @@ You can use the `useSession` hook from anywhere in your application (e.g. in a h
### Backend - API Route
To protect an API Route, you can use the [`getServerSession()`](/configuration/nextjs#unstable_getserversession) method.
To protect an API Route, you can use the [`unstable_getServerSession()`](/configuration/nextjs#unstable_getserversession) method.
```javascript title="pages/api/restricted.js" showLineNumbers
import { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
import { authOptions } from "./auth/[...nextauth]"
export default async (req, res) => {
const session = await getServerSession(req, res, authOptions)
const session = await unstable_getServerSession(req, res, authOptions)
if (session) {
res.send({

View File

@@ -68,12 +68,12 @@ For other patterns check out the [Next.js Middleware documentation](https://next
### Server Side
You can protect server side rendered pages using the `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, `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 { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
import { authOptions } from "./api/auth/[...nextauth]"
import { useSession } from "next-auth/react"
@@ -96,7 +96,7 @@ export default function Page() {
export async function getServerSideProps(context) {
return {
props: {
session: await getServerSession(
session: await unstable_getServerSession(
context.req,
context.res,
authOptions
@@ -128,16 +128,16 @@ export default function App({
## Securing API Routes
### Using getServerSession()
### Using unstable_getServerSession()
You can protect API routes using the `getServerSession()` method.
You can protect API routes using the `unstable_getServerSession()` method.
```js title="pages/api/get-session-example.js"
import { getServerSession } from "next-auth/next"
import { unstable_getServerSession } from "next-auth/next"
import { authOptions } from "./auth/[...nextauth]"
export default async (req, res) => {
const session = await getServerSession(req, res, authOptions)
const session = await unstable_getServerSession(req, res, authOptions)
if (session) {
// Signed in
console.log("Session", JSON.stringify(session, null, 2))

View File

@@ -1,6 +1,6 @@
{
"name": "next-auth",
"version": "4.19.2",
"version": "4.18.10",
"description": "Authentication for Next.js",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/next-auth.git",

View File

@@ -61,7 +61,7 @@ export function assertConfig(params: {
return new MissingSecret("Please define a `secret` in production.")
}
// req.query isn't defined when asserting `getServerSession` for example
// req.query isn't defined when asserting `unstable_getServerSession` for example
if (!req.query?.nextauth && !req.action) {
return new MissingAPIRoute(
"Cannot find [...nextauth].{js,ts} in `/pages/api/auth`. Make sure the filename is written correctly."

View File

@@ -1,5 +1,5 @@
import { openidClient } from "./client"
import { oAuth1Client, oAuth1TokenStore } from "./client-legacy"
import { oAuth1Client } from "./client-legacy"
import { createState } from "./state-handler"
import { createNonce } from "./nonce-handler"
import { createPKCE } from "./pkce-handler"
@@ -44,7 +44,7 @@ export default async function getAuthorizationUrl({
oauth_token_secret: tokens.oauth_token_secret,
...tokens.params,
})}`
oAuth1TokenStore.set(tokens.oauth_token, tokens.oauth_token_secret)
logger.debug("GET_AUTHORIZATION_URL", { url, provider })
return { redirect: url }
}

View File

@@ -1,6 +1,6 @@
import { TokenSet } from "openid-client"
import { openidClient } from "./client"
import { oAuth1Client, oAuth1TokenStore } from "./client-legacy"
import { oAuth1Client } from "./client-legacy"
import { useState } from "./state-handler"
import { usePKCECodeVerifier } from "./pkce-handler"
import { useNonce } from "./nonce-handler"
@@ -42,7 +42,7 @@ export default async function oAuthCallback(params: {
const { oauth_token, oauth_verifier } = query ?? {}
const tokens = (await (client as any).getOAuthAccessToken(
oauth_token,
oAuth1TokenStore.get(oauth_token),
null,
oauth_verifier
)) as TokenSet
let profile: Profile = await (client as any).get(
@@ -63,8 +63,6 @@ export default async function oAuthCallback(params: {
}
}
if (query?.oauth_token) oAuth1TokenStore.delete(query.oauth_token)
try {
const client = await openidClient(options)

View File

@@ -69,5 +69,3 @@ export function oAuth1Client(options: InternalOptions<"oauth">) {
}
return oauth1Client
}
export const oAuth1TokenStore = new Map()

View File

@@ -102,8 +102,8 @@ export default function ErrorPage(props: ErrorProps) {
}}
/>
)}
{theme?.logo && <img src={theme.logo} alt="Logo" className="logo" />}
<div className="card">
{theme?.logo && <img src={theme.logo} alt="Logo" className="logo" />}
<h1>{heading}</h1>
<div className="message">{message}</div>
{signin}

View File

@@ -49,13 +49,6 @@ export default function SigninPage(props: SignInServerPageParams) {
return false
})
if (typeof document !== "undefined" && theme.buttonText) {
document.documentElement.style.setProperty(
"--button-text-color",
theme.buttonText
)
}
if (typeof document !== "undefined" && theme.brandColor) {
document.documentElement.style.setProperty(
"--brand-color",
@@ -95,17 +88,7 @@ export default function SigninPage(props: SignInServerPageParams) {
}}
/>
)}
{theme.buttonText && (
<style
dangerouslySetInnerHTML={{
__html: `
:root {
--button-text-color: ${theme.buttonText}
}
`,
}}
/>
)}
{theme.logo && <img src={theme.logo} alt="Logo" className="logo" />}
<div className="card">
{error && (
<div className="error">
@@ -181,7 +164,7 @@ export default function SigninPage(props: SignInServerPageParams) {
placeholder="email@example.com"
required
/>
<button id="submitButton" type="submit">Sign in with {provider.name}</button>
<button type="submit">Sign in with {provider.name}</button>
</form>
)}
{provider.type === "credentials" && (

View File

@@ -23,24 +23,13 @@ export default function SignoutPage(props: SignoutProps) {
}}
/>
)}
{theme.buttonText && (
<style
dangerouslySetInnerHTML={{
__html: `
:root {
--button-text-color: ${theme.buttonText}
}
`,
}}
/>
)}
{theme.logo && <img src={theme.logo} alt="Logo" className="logo" />}
<div className="card">
{theme.logo && <img src={theme.logo} alt="Logo" className="logo" />}
<h1>Signout</h1>
<p>Are you sure you want to sign out?</p>
<form action={`${url}/signout`} method="POST">
<input type="hidden" name="csrfToken" value={csrfToken} />
<button id="submitButton" type="submit">Sign out</button>
<button type="submit">Sign out</button>
</form>
</div>
</div>

View File

@@ -22,8 +22,8 @@ export default function VerifyRequestPage(props: VerifyRequestPageProps) {
}}
/>
)}
{theme.logo && <img src={theme.logo} alt="Logo" className="logo" />}
<div className="card">
{theme.logo && <img src={theme.logo} alt="Logo" className="logo" />}
<h1>Check your email</h1>
<p>A sign in link has been sent to your email address.</p>
<p>

View File

@@ -8,8 +8,7 @@
.__next-auth-theme-auto,
.__next-auth-theme-light {
--color-background: #ececec;
--color-background-card: #fff;
--color-background: #fff;
--color-text: #000;
--color-primary: #444;
--color-control-border: #bbb;
@@ -19,8 +18,7 @@
}
.__next-auth-theme-dark {
--color-background: #161b22;
--color-background-card: #0d1117;
--color-background: #000;
--color-text: #fff;
--color-primary: #ccc;
--color-control-border: #555;
@@ -31,8 +29,7 @@
@media (prefers-color-scheme: dark) {
.__next-auth-theme-auto {
--color-background: #161b22;
--color-background-card: #0d1117;
--color-background: #000;
--color-text: #fff;
--color-primary: #ccc;
--color-control-border: #555;
@@ -81,9 +78,10 @@ input[type] {
width: 100%;
padding: 0.5rem 1rem;
border: var(--border-width) solid var(--color-control-border);
background: var(--color-background-card);
background: var(--color-background);
font-size: 1rem;
border-radius: var(--border-radius);
box-shadow: inset 0 0.1rem 0.2rem rgba(0, 0, 0, 0.2);
color: var(--color-text);
&:focus {
@@ -109,39 +107,41 @@ a.button {
}
}
button span {
flex-grow: 1;
}
button,
a.button {
margin: 0 0 0.75rem 0;
padding: 0.75rem 1rem;
color: var(--provider-color, var(--color-primary));
background-color: var(--provider-bg, var(--color-background-card));
background-color: var(--provider-bg, var(--color-background));
font-size: 1.1rem;
min-height: 62px;
border-color: rgba(0, 0, 0, 0.1);
border-radius: var(--border-radius);
transition: all 0.1s ease-in-out;
box-shadow: #000 0px 0px 0px 0px, #000 0px 0px 0px 0px,
rgba(0, 0, 0, 0.2) 0px 10px 15px -3px, rgba(0, 0, 0, 0.1) 0px 4px 6px -4px;
font-weight: 500;
position: relative;
display: flex;
align-items: center;
justify-content: center;
@media (max-width: 450px) {
font-size: 0.9rem;
&:has(img) {
justify-content: unset;
span {
flex-grow: 1;
}
}
&:hover {
cursor: pointer;
}
&:active {
box-shadow: 0 0.15rem 0.3rem rgba(0, 0, 0, 0.15),
inset 0 0.1rem 0.2rem var(--color-background),
inset 0 -0.1rem 0.1rem rgba(0, 0, 0, 0.1);
cursor: pointer;
}
#provider-logo {
width: 25px;
display: block;
}
#provider-logo-dark {
@@ -149,23 +149,20 @@ a.button {
}
}
#submitButton {
color: var(--button-text-color, var(--color-info-text));
background-color: var(--brand-color, var(--color-info));
width: 100%;
}
@media (prefers-color-scheme: dark) {
button,
a.button {
color: var(--provider-dark-color, var(--color-primary));
background-color: var(--provider-dark-bg, var(--color-background));
border: 1px solid #0d0d0d;
box-shadow: #000 0px 0px 0px 0px, #ccc 0px 0px 0px 0px,
rgba(255, 255, 255, 0.01) 0px 5px 5px -3px,
rgba(255, 255, 255, 0.05) 0px 4px 6px -4px;
}
#provider-logo {
display: none !important;
}
#provider-logo-dark {
width: 25px;
display: block !important;
}
}
@@ -192,6 +189,7 @@ a.site {
> div {
text-align: center;
padding: 0.5rem;
}
}
@@ -219,16 +217,16 @@ a.site {
display: block;
border: 0;
border-top: 1px solid var(--color-seperator);
margin: 2rem auto 1rem auto;
margin: 1.5em auto 0 auto;
overflow: visible;
&::before {
content: "or";
background: var(--color-background-card);
background: var(--color-background);
color: #888;
padding: 0 0.4rem;
position: relative;
top: -0.7rem;
top: -0.6rem;
}
}
@@ -236,7 +234,7 @@ a.site {
background: #f5f5f5;
font-weight: 500;
border-radius: 0.3rem;
background: var(--color-error);
background: var(--color-info);
p {
text-align: left;
@@ -262,26 +260,25 @@ a.site {
max-width: 300px;
}
}
.signout {
.message {
margin-bottom: 1.5rem;
}
}
.logo {
display: inline-block;
max-width: 150px;
margin-top: 20px;
margin-bottom: 25px;
max-height: 70px;
margin-top: 100px;
max-width: 300px;
max-height: 150px;
}
.card {
@media screen and (min-width: 450px) {
width: 350px;
}
@media screen and (max-width: 450px) {
width: 200px;
}
margin: 20px 0 20px 0;
background-color: var(--color-background-card);
border-radius: 30px;
max-width: max-content;
border: 1px solid var(--color-control-border);
border-radius: 5px;
padding: 20px 50px;
margin: 50px auto;
.header {
color: var(--color-primary);
@@ -289,5 +286,5 @@ a.site {
}
.section-header {
color: var(--color-text);
color: var(--brand-color, var(--color-text));
}

View File

@@ -82,6 +82,7 @@ function NextAuth(
export default NextAuth
let experimentalWarningShown = false
let experimentalRSCWarningShown = false
type GetServerSessionOptions = Partial<Omit<AuthOptions, "callbacks">> & {
@@ -90,18 +91,28 @@ type GetServerSessionOptions = Partial<Omit<AuthOptions, "callbacks">> & {
}
}
type GetServerSessionParams<O extends GetServerSessionOptions> =
| [GetServerSidePropsContext["req"], GetServerSidePropsContext["res"], O]
| [NextApiRequest, NextApiResponse, O]
| [O]
| []
export async function getServerSession<
export async function unstable_getServerSession<
O extends GetServerSessionOptions,
R = O["callbacks"] extends { session: (...args: any[]) => infer U }
? U
: Session
>(...args: GetServerSessionParams<O>): Promise<R | null> {
>(
...args:
| [GetServerSidePropsContext["req"], GetServerSidePropsContext["res"], O]
| [NextApiRequest, NextApiResponse, O]
| [O]
| []
): Promise<R | null> {
if (!experimentalWarningShown && process.env.NODE_ENV !== "production") {
console.warn(
"[next-auth][warn][EXPERIMENTAL_API]",
"\n`unstable_getServerSession` is experimental and may be removed or changed in the future, as the name suggested.",
`\nhttps://next-auth.js.org/configuration/nextjs#unstable_getServerSession}`,
`\nhttps://next-auth.js.org/warnings#EXPERIMENTAL_API`
)
experimentalWarningShown = true
}
const isRSC = args.length === 0 || args.length === 1
if (
!experimentalRSCWarningShown &&
@@ -110,8 +121,8 @@ export async function getServerSession<
) {
console.warn(
"[next-auth][warn][EXPERIMENTAL_API]",
"\n`getServerSession` is used in a React Server Component.",
`\nhttps://next-auth.js.org/configuration/nextjs#getServerSession}`,
"\n`unstable_getServerSession` is used in a React Server Component.",
`\nhttps://next-auth.js.org/configuration/nextjs#unstable_getServerSession}`,
`\nhttps://next-auth.js.org/warnings#EXPERIMENTAL_API`
)
experimentalRSCWarningShown = true
@@ -167,25 +178,6 @@ export async function getServerSession<
return null
}
let deprecatedWarningShown = false
/** @deprecated renamed to `getServerSession` */
export async function unstable_getServerSession<
O extends GetServerSessionOptions,
R = O["callbacks"] extends { session: (...args: any[]) => infer U }
? U
: Session
>(...args: GetServerSessionParams<O>): Promise<R | null> {
if (!deprecatedWarningShown && process.env.NODE_ENV !== "production") {
console.warn(
"`unstable_getServerSession` has been renamed to `getServerSession`."
)
deprecatedWarningShown = true
}
return await getServerSession(...args)
}
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace NodeJS {

View File

@@ -1,6 +1,6 @@
import * as core from "../src/core"
import { MissingSecret } from "../src/core/errors"
import { getServerSession } from "../src/next"
import { unstable_getServerSession } from "../src/next"
import { mockLogger } from "./lib"
const originalWarn = console.warn
@@ -27,7 +27,7 @@ afterEach(() => {
describe("Treat secret correctly", () => {
it("Read from NEXTAUTH_SECRET", async () => {
process.env.NEXTAUTH_SECRET = "secret"
await getServerSession(req, res, { providers: [], logger })
await unstable_getServerSession(req, res, { providers: [], logger })
expect(logger.error).toBeCalledTimes(0)
expect(logger.error).not.toBeCalledWith("NO_SECRET")
@@ -36,7 +36,7 @@ describe("Treat secret correctly", () => {
})
it("Read from options.secret", async () => {
await getServerSession(req, res, {
await unstable_getServerSession(req, res, {
providers: [],
logger,
secret: "secret",
@@ -51,12 +51,30 @@ describe("Treat secret correctly", () => {
"There is a problem with the server configuration. Check the server logs for more information."
)
await expect(
getServerSession(req, res, { providers: [], logger })
unstable_getServerSession(req, res, { providers: [], logger })
).rejects.toThrowError(configError)
expect(logger.error).toBeCalledTimes(1)
expect(logger.error).toBeCalledWith("NO_SECRET", expect.any(MissingSecret))
})
it("Only logs warning once and in development", async () => {
process.env.NEXTAUTH_SECRET = "secret"
// Expect console.warn to NOT be called due to NODE_ENV=production
await unstable_getServerSession(req, res, { providers: [], logger })
expect(console.warn).toBeCalledTimes(0)
// Expect console.warn to be called ONCE due to NODE_ENV=development
// @ts-expect-error
process.env.NODE_ENV = "development"
await unstable_getServerSession(req, res, { providers: [], logger })
expect(console.warn).toBeCalledTimes(1)
// Expect console.warn to be still only be called ONCE
await unstable_getServerSession(req, res, { providers: [], logger })
expect(console.warn).toBeCalledTimes(1)
delete process.env.NEXTAUTH_SECRET
})
})
describe("Return correct data", () => {
@@ -69,7 +87,7 @@ describe("Return correct data", () => {
// @ts-expect-error
spy.mockReturnValue({ body: {} })
const session = await getServerSession(req, res, {
const session = await unstable_getServerSession(req, res, {
providers: [],
logger,
secret: "secret",
@@ -95,7 +113,7 @@ describe("Return correct data", () => {
// @ts-expect-error
spy.mockReturnValue(mockedResponse)
const session = await getServerSession(req, res, {
const session = await unstable_getServerSession(req, res, {
providers: [],
logger,
secret: "secret",