Skip to content

Commit d2d4553

Browse files
committed
🕷️
1 parent 8722569 commit d2d4553

File tree

12 files changed

+105
-50
lines changed

12 files changed

+105
-50
lines changed

app1/ui/Home.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ export default function Home() {
2828
onSelectAccount={(session) => console.log(session)}
2929
session={sessions[0]}
3030
sessions={sessions}
31-
signOut={() => {
32-
window.location.href = `https://auth.example.local/auth/signout?id_token_hint=${sessions[0]?.idToken}&return_url=https://app.example.local/app1`;
33-
}}
3431
/>
3532
</div>
3633
</nav>

app1/ui/components/ProfileImage.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ export default function ProfileImage(props: {
88
session: any;
99
sessions: any[];
1010
onSelectAccount: (session: any) => void;
11-
signOut: (sessionId: string) => void;
1211
}) {
13-
const { session, sessions, onSelectAccount, signOut } = props;
12+
const { session, sessions } = props;
1413
const router = useRouter();
1514

1615
const user = {
@@ -50,7 +49,6 @@ export default function ProfileImage(props: {
5049
{() => (
5150
<button
5251
onClick={() => {
53-
// onSelectAccount(session);
5452
router.push(`/account/${index}`);
5553
}}
5654
className={`group flex items-center w-full px-2 py-2 text-sm`}
@@ -76,7 +74,6 @@ export default function ProfileImage(props: {
7674
className={`group flex justify-center items-center w-full px-2 py-2 text-sm`}
7775
onClick={() => {
7876
const params = new URLSearchParams({
79-
// login_hint: 'username',
8077
prompt: "select_account",
8178
scope: [
8279
"openid",
@@ -91,7 +88,7 @@ export default function ProfileImage(props: {
9188
return_url: "https://app.example.local/app1",
9289
});
9390

94-
window.location.href = `https://auth.example.local/auth/signin?${params}`;
91+
window.location.href = `https://auth.example.local/auth/signin/portal?${params}`;
9592
}}
9693
>
9794
+ Add other account
@@ -103,7 +100,17 @@ export default function ProfileImage(props: {
103100
{() => (
104101
<button
105102
className={`group flex justify-center items-center w-full px-2 py-2 text-sm`}
106-
onClick={() => signOut(session.id)}
103+
onClick={() => {
104+
const params = new URLSearchParams({
105+
return_url: "https://app.example.local/app1",
106+
});
107+
108+
if (session?.idToken) {
109+
params.set("id_token_hint", session.idToken);
110+
}
111+
112+
window.location.href = `https://auth.example.local/auth/signout/portal?${params}`;
113+
}}
107114
>
108115
Logout
109116
</button>

app2/ui/Home.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { useEffect, useState } from "react";
33

44
export default function Home() {
5-
const [sessions, setSessions] = useState([]);
5+
const [sessions, setSessions] = useState<any[]>([]);
66

77
useEffect(() => {
88
reloadSessions();
@@ -37,7 +37,7 @@ export default function Home() {
3737
return_url: "https://app.example.local/app2",
3838
});
3939

40-
window.location.href = `https://auth.example.local/auth/signin?${params}`;
40+
window.location.href = `https://auth.example.local/auth/signin/zitadel?${params}`;
4141
}}
4242
>
4343
Login
@@ -48,7 +48,11 @@ export default function Home() {
4848
return_url: "https://app.example.local/app2",
4949
});
5050

51-
window.location.href = `https://auth.example.local/auth/signout?${params}`;
51+
if (sessions[0]?.idToken) {
52+
params.set("id_token_hint", sessions[0].idToken);
53+
}
54+
55+
window.location.href = `https://auth.example.local/auth/signout/zitadel?${params}`;
5256
}}
5357
>
5458
Logout

auth/app/api/auth/callback/route.ts renamed to auth/app/api/auth/callback/[provider]/route.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ import { NextRequest, NextResponse } from "next/server";
1414
import { URLSearchParams } from "url";
1515
import { v4 as uuid } from "uuid";
1616

17-
async function handler(request: NextRequest) {
17+
async function handler(
18+
request: NextRequest,
19+
{ params }: { params: { provider: "portal" | "zitadel" } }
20+
) {
1821
try {
1922
const code = request.nextUrl.searchParams.get("code");
2023
const state = request.nextUrl.searchParams.get("state");
@@ -36,15 +39,18 @@ async function handler(request: NextRequest) {
3639
if (redirectCookie.value !== configuration.redirectUrl)
3740
throw new Error("Invalid redirect url");
3841

42+
const provider = params.provider;
43+
if (!provider) throw new Error("provider not found");
44+
3945
const tokenParams = new URLSearchParams();
4046
tokenParams.append("code", code as string);
4147
tokenParams.append("grant_type", "authorization_code");
42-
tokenParams.append("client_id", configuration.portal.clientId);
48+
tokenParams.append("client_id", configuration[provider].clientId);
4349
tokenParams.append("redirect_uri", configuration.redirectUrl);
4450
tokenParams.append("code_verifier", codeVerifierCookie.value);
4551

4652
const wellKnownResponse = await fetch(
47-
`${configuration.portal.issuer}/.well-known/openid-configuration`
53+
`${configuration[provider].issuer}/.well-known/openid-configuration`
4854
);
4955

5056
const wellKnown = (await wellKnownResponse.json()) as {

auth/app/api/auth/signin/route.ts renamed to auth/app/api/auth/signin/[provider]/route.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ import { cookies } from "next/headers";
1616
import { NextRequest, NextResponse } from "next/server";
1717
import { URLSearchParams } from "url";
1818

19-
export async function POST(request: NextRequest) {
19+
export async function POST(
20+
request: NextRequest,
21+
{ params }: { params: { provider: "portal" | "zitadel" } }
22+
) {
2023
const body = (await request.json()) as {
2124
csrfToken: string;
2225
scope: string;
@@ -26,14 +29,17 @@ export async function POST(request: NextRequest) {
2629
};
2730
const { csrfToken, scope, returnUrl, prompt, loginHint } = body;
2831

32+
const provider = params.provider;
33+
if (!provider) throw new Error("provider not found");
34+
2935
const requestCookie = cookies();
3036

3137
const csrfTokenCookie = requestCookie.get(csrfTokenCookieName);
3238
if (!csrfTokenCookie) throw new Error("csrfToken cookie not found");
3339
if (csrfTokenCookie.value !== csrfToken) throw new Error("Invalid csrfToken");
3440

3541
const wellKnownResponse = await fetch(
36-
`${configuration.portal.issuer}/.well-known/openid-configuration`
42+
`${configuration[provider].issuer}/.well-known/openid-configuration`
3743
);
3844

3945
const wellKnown = (await wellKnownResponse.json()) as {
@@ -52,18 +58,18 @@ export async function POST(request: NextRequest) {
5258
const codeChallenge = generateCodeChallenge(codeVerifier);
5359
const state = generateState();
5460

55-
const params = new URLSearchParams({
61+
const requestParams = new URLSearchParams({
5662
code_challenge: codeChallenge,
5763
code_challenge_method: "S256",
58-
client_id: configuration.portal.clientId,
64+
client_id: configuration[provider].clientId,
5965
redirect_uri: configuration.redirectUrl,
6066
response_type: "code",
6167
scope,
6268
state,
6369
});
6470

65-
if (prompt) params.set("prompt", prompt);
66-
if (loginHint) params.set("login_hint", loginHint);
71+
if (prompt) requestParams.set("prompt", prompt);
72+
if (loginHint) requestParams.set("login_hint", loginHint);
6773

6874
if (returnUrl) setShortLiveCookie(returnUrlCookieName, returnUrl);
6975
setShortLiveCookie(stateCookieName, state);

auth/app/api/auth/signout/route.ts renamed to auth/app/api/auth/signout/[provider]/route.ts

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import { Prisma } from "@prisma/client";
66
import { cookies } from "next/headers";
77
import { NextRequest, NextResponse } from "next/server";
88

9-
export async function POST(request: NextRequest) {
9+
export async function POST(
10+
request: NextRequest,
11+
{ params }: { params: { provider: "portal" | "zitadel" } }
12+
) {
1013
try {
1114
const body = (await request.json()) as {
1215
returnUrl?: string;
@@ -17,12 +20,11 @@ export async function POST(request: NextRequest) {
1720
};
1821
const { returnUrl, idTokenHint, state } = body;
1922

20-
const requestCookie = cookies();
21-
const authSessionCookie = requestCookie.get(authSessionCookieName);
22-
const authSession = authSessionCookie?.value;
23+
const provider = params.provider;
24+
if (!provider) throw new Error("provider not found");
2325

2426
const wellKnownResponse = await fetch(
25-
`${configuration.portal.issuer}/.well-known/openid-configuration`
27+
`${configuration[provider].issuer}/.well-known/openid-configuration`
2628
);
2729

2830
const wellKnown = (await wellKnownResponse.json()) as {
@@ -37,28 +39,33 @@ export async function POST(request: NextRequest) {
3739
throw { code: wellKnownResponse.status, details: wellKnown };
3840
}
3941

40-
const params = new URLSearchParams({
41-
client_id: configuration.portal.clientId,
42+
const requestParams = new URLSearchParams({
43+
client_id: configuration[provider].clientId,
4244
post_logout_redirect_uri: configuration.postLogoutRedirectUri,
4345
});
4446

45-
if (state) params.set("state", state);
47+
if (state) requestParams.set("state", state);
48+
if (idTokenHint) requestParams.set("id_token_hint", idTokenHint);
4649

47-
const sessionWhereInput: Prisma.SessionWhereInput = {
48-
authSession: authSessionCookie?.value,
49-
};
50+
const requestCookie = cookies();
51+
const authSessionCookie = requestCookie.get(authSessionCookieName);
5052

51-
if (idTokenHint) {
52-
params.set("id_token_hint", idTokenHint);
53-
sessionWhereInput.idToken = idTokenHint;
54-
}
53+
if (authSessionCookie?.value) {
54+
const sessionWhereInput: Prisma.SessionWhereInput = {
55+
authSession: authSessionCookie.value,
56+
};
5557

56-
await prisma.session.updateMany({
57-
where: sessionWhereInput,
58-
data: {
59-
deletedAt: new Date(),
60-
},
61-
});
58+
if (idTokenHint) {
59+
sessionWhereInput.idToken = idTokenHint;
60+
}
61+
62+
await prisma.session.updateMany({
63+
where: sessionWhereInput,
64+
data: {
65+
deletedAt: new Date(),
66+
},
67+
});
68+
}
6269

6370
if (returnUrl) setShortLiveCookie(returnUrlCookieName, returnUrl);
6471

auth/app/auth/signin/page.tsx renamed to auth/app/auth/signin/[provider]/page.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@ import SignIn from "@/ui/SignIn";
22

33
export default async function Page({
44
searchParams,
5+
params,
56
}: {
67
searchParams: {
78
return_url?: string;
89
prompt?: string;
910
scope?: string;
1011
login_hint?: string;
1112
};
13+
params: { provider: string };
1214
}) {
1315
return (
1416
<SignIn
17+
provider={params.provider}
1518
returnUrl={searchParams.return_url}
1619
prompt={searchParams.prompt}
1720
scope={searchParams.scope}

auth/app/auth/signout/page.tsx renamed to auth/app/auth/signout/[provider]/page.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import SignOut from "@/ui/SignOut";
22

33
export default async function Page({
44
searchParams,
5+
params,
56
}: {
67
searchParams: {
78
return_url?: string;
@@ -10,9 +11,12 @@ export default async function Page({
1011
post_logoutRedirect_uri?: string;
1112
state?: string;
1213
};
14+
params: { provider: string };
1315
}) {
16+
console.log(`debug:params`, params);
1417
return (
1518
<SignOut
19+
provider={params.provider}
1620
returnUrl={searchParams.return_url}
1721
idTokenHint={searchParams.id_token_hint}
1822
clientId={searchParams.client_id}

auth/configuration.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,13 @@ const schema = z.object({
2424
portal: z.object({
2525
clientId: z.string(),
2626
issuer: z.string(),
27-
redirectUrl: z.string(),
2827
}),
28+
zitadel: z.object({
29+
clientId: z.string(),
30+
issuer: z.string(),
31+
}),
32+
redirectUrl: z.string(),
33+
postLogoutRedirectUri: z.string(),
2934
});
3035

3136
const configuration = {

auth/prisma/dev.db

0 Bytes
Binary file not shown.

auth/ui/SignIn.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ import { useEffect } from "react";
33
import { useRouter } from "next/navigation";
44

55
export default function SignIn(props: {
6+
provider: string;
67
returnUrl?: string;
78
prompt?: string;
89
scope?: string;
910
loginHint?: string;
1011
}) {
1112
const router = useRouter();
12-
const { returnUrl, prompt, scope, loginHint } = props;
13+
const { provider, returnUrl, prompt, scope, loginHint } = props;
1314

1415
useEffect(() => {
1516
fetch(`https://auth.example.local/api/auth/csrf`, {
@@ -19,7 +20,7 @@ export default function SignIn(props: {
1920
.then(async ({ csrfToken }) => {
2021
if (csrfToken) {
2122
const result = await fetch(
22-
`https://auth.example.local/api/auth/signin`,
23+
`https://auth.example.local/api/auth/signin/${provider}`,
2324
{
2425
method: "POST",
2526
body: JSON.stringify({
@@ -35,7 +36,7 @@ export default function SignIn(props: {
3536
if (result.authorizeUrl) router.replace(result.authorizeUrl);
3637
}
3738
});
38-
}, [loginHint, prompt, returnUrl, router, scope]);
39+
}, [loginHint, prompt, provider, returnUrl, router, scope]);
3940

4041
return <div>Loading...</div>;
4142
}

auth/ui/SignOut.tsx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,25 @@ import { useEffect } from "react";
33
import { useRouter } from "next/navigation";
44

55
export default function SignOut(props: {
6+
provider: string;
67
returnUrl?: string;
78
idTokenHint?: string;
89
clientId?: string;
910
postLogoutRedirectUri?: string;
1011
state?: string;
1112
}) {
12-
const { returnUrl, idTokenHint, clientId, postLogoutRedirectUri, state } =
13-
props;
13+
const {
14+
provider,
15+
returnUrl,
16+
idTokenHint,
17+
clientId,
18+
postLogoutRedirectUri,
19+
state,
20+
} = props;
1421
const router = useRouter();
1522

1623
useEffect(() => {
17-
fetch(`https://auth.example.local/api/auth/signout`, {
24+
fetch(`https://auth.example.local/api/auth/signout/${provider}`, {
1825
method: "POST",
1926
body: JSON.stringify({
2027
returnUrl,
@@ -28,7 +35,15 @@ export default function SignOut(props: {
2835
.then(({ endSessionUrl }) => {
2936
if (endSessionUrl) router.replace(endSessionUrl);
3037
});
31-
}, [clientId, idTokenHint, postLogoutRedirectUri, returnUrl, router, state]);
38+
}, [
39+
clientId,
40+
idTokenHint,
41+
postLogoutRedirectUri,
42+
provider,
43+
returnUrl,
44+
router,
45+
state,
46+
]);
3247

3348
return <div>Loading...</div>;
3449
}

0 commit comments

Comments
 (0)