Skip to content

Commit 773cf7a

Browse files
committed
docs(auth): robust Next.js callback example
Use handleRedirectCallback() instead of relying solely on a reactive useSession: await the redirect exchange so the page redirects only when done, show the error instead of hanging on 'Signing you in…', and use the returned returnTo (set via signInWithOauthConnection({ returnTo })) to send the user back where they were — no sessionStorage bookkeeping.
1 parent 9113664 commit 773cf7a

1 file changed

Lines changed: 36 additions & 11 deletions

File tree

content/auth/quickstart/nextjs.mdx

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,12 @@ export default function App({ Component, pageProps }: AppProps) {
114114

115115
## Add the callback route
116116

117-
After login the user is redirected to the callback URL you registered on your Client. `@faable/auth-js` reads the tokens from the URL automatically; the route just needs to mount the SDK and send the user somewhere afterwards.
117+
After login the user is redirected to the callback URL you registered on your Client. `@faable/auth-js` reads the tokens from the URL automatically, but your callback route should **await** that processing so it can:
118+
119+
- redirect **only once** the token exchange has finished, and
120+
- show an error instead of getting stuck on "Signing you in…" if the exchange fails (e.g. an expired login attempt).
121+
122+
Call `handleRedirectCallback()` for exactly that. It returns `{ error, returnTo }`: on success send the user onward (to `returnTo` if you set one when starting the login — see below), and on failure surface `error.message`.
118123

119124
<Tabs items={['App Router', 'Pages Router']}>
120125
<Tabs.Tab>
@@ -123,18 +128,22 @@ After login the user is redirected to the callback URL you registered on your Cl
123128
// app/callback/page.tsx
124129
"use client";
125130

126-
import { useEffect } from "react";
131+
import { useEffect, useState } from "react";
127132
import { useRouter } from "next/navigation";
128-
import { useSession } from "@faable/auth-helpers-react";
133+
import { faableauth } from "../../lib/faable";
129134

130135
export default function CallbackPage() {
131136
const router = useRouter();
132-
const session = useSession();
137+
const [error, setError] = useState<string | null>(null);
133138

134139
useEffect(() => {
135-
if (session) router.replace("/");
136-
}, [session, router]);
140+
faableauth.handleRedirectCallback().then(({ error, returnTo }) => {
141+
if (error) setError(error.message);
142+
else router.replace(returnTo ?? "/");
143+
});
144+
}, [router]);
137145

146+
if (error) return <p>Sign-in failed: {error}</p>;
138147
return <p>Signing you in…</p>;
139148
}
140149
```
@@ -144,25 +153,41 @@ export default function CallbackPage() {
144153

145154
```tsx
146155
// pages/callback.tsx
147-
import { useEffect } from "react";
156+
import { useEffect, useState } from "react";
148157
import { useRouter } from "next/router";
149-
import { useSession } from "@faable/auth-helpers-react";
158+
import { faableauth } from "../lib/faable";
150159

151160
export default function CallbackPage() {
152161
const router = useRouter();
153-
const session = useSession();
162+
const [error, setError] = useState<string | null>(null);
154163

155164
useEffect(() => {
156-
if (session) router.replace("/");
157-
}, [session, router]);
165+
faableauth.handleRedirectCallback().then(({ error, returnTo }) => {
166+
if (error) setError(error.message);
167+
else router.replace(returnTo ?? "/");
168+
});
169+
}, [router]);
158170

171+
if (error) return <p>Sign-in failed: {error}</p>;
159172
return <p>Signing you in…</p>;
160173
}
161174
```
162175

163176
</Tabs.Tab>
164177
</Tabs>
165178

179+
> **Returning the user to where they were.** Pass `returnTo` when you start the
180+
> login and it round-trips back to you here — no `sessionStorage` bookkeeping
181+
> needed. It is stored locally next to the PKCE verifier and never sent to the
182+
> server:
183+
>
184+
> ```ts
185+
> await faableauth.signInWithOauthConnection({
186+
> redirectTo: window.location.origin + "/callback",
187+
> returnTo: "/dashboard",
188+
> });
189+
> ```
190+
166191
## Accessing user state
167192
168193
Anywhere inside the provider, use the `useSession` and `useUser` hooks to read the current session and user profile. Call `signInWithOauthConnection` on the client to start the login, and `signOut` to clear it.

0 commit comments

Comments
 (0)