Skip to content

Commit 1ac24be

Browse files
committed
fix: stateless sign out
1 parent fed34f7 commit 1ac24be

File tree

5 files changed

+60
-28
lines changed

5 files changed

+60
-28
lines changed

src/app/dashboard/page.tsx

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
1-
import { headers } from "next/headers";
2-
import { redirect } from "next/navigation";
3-
import { auth } from "@/lib/auth";
1+
"use client";
42

5-
export default async function DashboardPage() {
6-
const session = await auth.api.getSession({
7-
headers: await headers(),
8-
});
3+
import { useRouter } from "next/navigation";
4+
import { useEffect, useState } from "react";
5+
import { signOut, useSession } from "@/lib/auth-client";
96

10-
if (!session) {
11-
redirect("/login");
7+
export default function DashboardPage() {
8+
const router = useRouter();
9+
const { data: session, isPending } = useSession();
10+
const [isSigningOut, setIsSigningOut] = useState(false);
11+
12+
useEffect(() => {
13+
if (!isPending && !session) {
14+
router.push("/sign-in");
15+
}
16+
}, [session, isPending, router]);
17+
18+
const handleSignOut = async () => {
19+
setIsSigningOut(true);
20+
try {
21+
await signOut();
22+
} catch (error) {
23+
console.error("Sign-out error:", error);
24+
setIsSigningOut(false);
25+
}
26+
};
27+
28+
if (isPending || !session) {
29+
return null;
1230
}
1331

1432
return (
@@ -36,14 +54,14 @@ export default async function DashboardPage() {
3654
</div>
3755
</div>
3856

39-
<form action="/api/auth/sign-out" method="POST">
40-
<button
41-
type="submit"
42-
className="rounded-full bg-red-600 px-6 py-3 text-white transition-colors hover:bg-red-700"
43-
>
44-
Sign Out
45-
</button>
46-
</form>
57+
<button
58+
type="button"
59+
onClick={handleSignOut}
60+
disabled={isSigningOut}
61+
className="rounded-full bg-red-600 px-6 py-3 text-white transition-colors hover:bg-red-700 disabled:opacity-50"
62+
>
63+
{isSigningOut ? "Signing Out..." : "Sign Out"}
64+
</button>
4765
</main>
4866
</div>
4967
);

src/app/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ export default function Home() {
3333
) : (
3434
<div className="flex flex-col items-center gap-4">
3535
<p className="text-zinc-600 dark:text-zinc-400">
36-
Please log in to access the application
36+
Please sign in to access the application
3737
</p>
3838
<Link
39-
href="/login"
39+
href="/sign-in"
4040
className="rounded-full bg-black px-6 py-3 text-white transition-colors hover:bg-zinc-800 dark:bg-white dark:text-black dark:hover:bg-zinc-200"
4141
>
42-
Log In
42+
Sign In
4343
</Link>
4444
</div>
4545
)}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ const OIDC_PROVIDER_ID = process.env.NEXT_PUBLIC_OIDC_PROVIDER_ID || "oidc";
66
const OIDC_PROVIDER_NAME =
77
process.env.NEXT_PUBLIC_OIDC_PROVIDER_NAME || "OIDC Provider";
88

9-
export default function LoginPage() {
10-
const handleOIDCLogin = async () => {
9+
export default function SignInPage() {
10+
const handleOIDCSignIn = async () => {
1111
try {
1212
console.log("Initiating OIDC sign-in...");
1313
const { data, error } = await authClient.signIn.oauth2({
@@ -35,7 +35,7 @@ export default function LoginPage() {
3535
<div className="flex min-h-screen items-center justify-center bg-zinc-50 dark:bg-black">
3636
<main className="flex flex-col items-center gap-8 rounded-lg bg-white p-12 shadow-lg dark:bg-zinc-900">
3737
<h1 className="text-3xl font-bold text-black dark:text-white">
38-
Log In
38+
Sign In
3939
</h1>
4040

4141
<p className="text-center text-zinc-600 dark:text-zinc-400">
@@ -44,7 +44,7 @@ export default function LoginPage() {
4444

4545
<button
4646
type="button"
47-
onClick={handleOIDCLogin}
47+
onClick={handleOIDCSignIn}
4848
className="rounded-full bg-black px-8 py-3 text-white transition-colors hover:bg-zinc-800 dark:bg-white dark:text-black dark:hover:bg-zinc-200"
4949
>
5050
Sign In with {OIDC_PROVIDER_NAME}

src/lib/auth-client.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,18 @@ export const authClient = createAuthClient({
77
plugins: [genericOAuthClient()],
88
});
99

10-
// You can also export specific methods if you prefer
11-
export const { signIn, signOut, useSession } = authClient;
10+
export const { signIn, useSession } = authClient;
11+
12+
export const signOut = async (options?: { redirectTo?: string }) => {
13+
const redirectUri = options?.redirectTo || "/sign-in";
14+
15+
// Note: This does NOT logout from Okta SSO session
16+
// User will be automatically re-authenticated on next sign-in (SSO behavior)
17+
await authClient.signOut({
18+
fetchOptions: {
19+
onSuccess: () => {
20+
window.location.href = redirectUri;
21+
},
22+
},
23+
});
24+
};

src/lib/auth.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { BetterAuthOptions } from "better-auth";
12
import { betterAuth } from "better-auth";
23
import { genericOAuth } from "better-auth/plugins";
34

@@ -37,9 +38,9 @@ export const auth = betterAuth({
3738
clientId: process.env.OIDC_CLIENT_ID || "",
3839
clientSecret: process.env.OIDC_CLIENT_SECRET || "",
3940
scopes: ["openid", "email", "profile"],
40-
pkce: false,
41+
pkce: true,
4142
},
4243
],
4344
}),
4445
],
45-
});
46+
} as BetterAuthOptions);

0 commit comments

Comments
 (0)