Skip to content

Commit 74858dc

Browse files
committed
Trying to fix auth mfa
1 parent 7ea22ba commit 74858dc

3 files changed

Lines changed: 79 additions & 10 deletions

File tree

src/app/login/route.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,9 @@ export async function GET(request: NextRequest) {
9393

9494
const sessionId = searchParams.get("sessionId");
9595

96-
// TODO: find a better way to handle _rsc (react server components) requests and block them to avoid conflicts when creating oidc callback
9796
const _rsc = searchParams.get("_rsc");
9897
if (_rsc) {
99-
return NextResponse.json({ error: "No _rsc supported" }, { status: 500 });
98+
return NextResponse.json({ error: "RSC requests not supported on login endpoint" }, { status: 400 });
10099
}
101100

102101
const sessionCookies = await getAllSessions();

src/lib/oidc.ts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Cookie } from "@/lib/cookies";
22
import { sendLoginname, SendLoginnameCommand } from "@/lib/server/loginname";
3-
import { createCallback, getLoginSettings } from "@/lib/zitadel";
3+
import { createCallback, getLoginSettings, listAuthenticationMethodTypes } from "@/lib/zitadel";
44
import { create } from "@zitadel/client";
55
import {
66
CreateCallbackRequestSchema,
@@ -10,6 +10,7 @@ import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb";
1010
import { NextRequest, NextResponse } from "next/server";
1111
import { constructUrl } from "./service-url";
1212
import { isSessionValid } from "./session";
13+
import { checkMFAFactors } from "./verify-helper";
1314

1415
type LoginWithOIDCAndSession = {
1516
serviceUrl: string;
@@ -44,8 +45,37 @@ export async function loginWithOIDCAndSession({
4445
console.log("Session is valid:", isValid);
4546

4647
if (!isValid && selectedSession.factors?.user) {
48+
// Check if user has already authenticated via IDP but needs MFA
49+
if (selectedSession.factors?.intent?.verifiedAt) {
50+
console.log("User has IDP authentication, checking MFA factors...");
51+
52+
const methods = await listAuthenticationMethodTypes({
53+
serviceUrl,
54+
userId: selectedSession.factors.user.id,
55+
});
56+
57+
const loginSettings = await getLoginSettings({
58+
serviceUrl,
59+
organization: selectedSession.factors?.user?.organizationId,
60+
});
61+
62+
const mfaFactorCheck = await checkMFAFactors(
63+
serviceUrl,
64+
selectedSession,
65+
loginSettings,
66+
methods.authMethodTypes,
67+
selectedSession.factors?.user?.organizationId,
68+
`oidc_${authRequest}`,
69+
);
70+
71+
if (mfaFactorCheck?.redirect) {
72+
console.log("Redirecting to MFA:", mfaFactorCheck.redirect);
73+
const absoluteUrl = constructUrl(request, mfaFactorCheck.redirect);
74+
return NextResponse.redirect(absoluteUrl.toString());
75+
}
76+
}
77+
4778
// if the session is not valid anymore, we need to redirect the user to re-authenticate /
48-
// TODO: handle IDP intent direcly if available
4979
const command: SendLoginnameCommand = {
5080
loginName: selectedSession.factors.user?.loginName,
5181
organization: selectedSession.factors?.user?.organizationId,
@@ -55,8 +85,13 @@ export async function loginWithOIDCAndSession({
5585
const res = await sendLoginname(command);
5686

5787
if (res && "redirect" in res && res?.redirect) {
58-
const absoluteUrl = constructUrl(request, res.redirect);
59-
return NextResponse.redirect(absoluteUrl.toString());
88+
// Check if the redirect URL is already a full URL
89+
if (res.redirect.startsWith("http://") || res.redirect.startsWith("https://")) {
90+
return NextResponse.redirect(res.redirect);
91+
} else {
92+
const absoluteUrl = constructUrl(request, res.redirect);
93+
return NextResponse.redirect(absoluteUrl.toString());
94+
}
6095
}
6196
}
6297

src/lib/saml.ts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Cookie } from "@/lib/cookies";
22
import { sendLoginname, SendLoginnameCommand } from "@/lib/server/loginname";
3-
import { createResponse, getLoginSettings } from "@/lib/zitadel";
3+
import { createResponse, getLoginSettings, listAuthenticationMethodTypes } from "@/lib/zitadel";
44
import { create } from "@zitadel/client";
55
import { CreateResponseRequestSchema } from "@zitadel/proto/zitadel/saml/v2/saml_service_pb";
66
import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb";
@@ -9,6 +9,7 @@ import { NextRequest, NextResponse } from "next/server";
99
import { v4 as uuidv4 } from "uuid";
1010
import { constructUrl } from "./service-url";
1111
import { isSessionValid } from "./session";
12+
import { checkMFAFactors } from "./verify-helper";
1213

1314
type LoginWithSAMLAndSession = {
1415
serviceUrl: string;
@@ -118,8 +119,37 @@ export async function loginWithSAMLAndSession({
118119
console.log("Session is valid:", isValid);
119120

120121
if (!isValid && selectedSession.factors?.user) {
122+
// Check if user has already authenticated via IDP but needs MFA
123+
if (selectedSession.factors?.intent?.verifiedAt) {
124+
console.log("User has IDP authentication, checking MFA factors...");
125+
126+
const methods = await listAuthenticationMethodTypes({
127+
serviceUrl,
128+
userId: selectedSession.factors.user.id,
129+
});
130+
131+
const loginSettings = await getLoginSettings({
132+
serviceUrl,
133+
organization: selectedSession.factors?.user?.organizationId,
134+
});
135+
136+
const mfaFactorCheck = await checkMFAFactors(
137+
serviceUrl,
138+
selectedSession,
139+
loginSettings,
140+
methods.authMethodTypes,
141+
selectedSession.factors?.user?.organizationId,
142+
`saml_${samlRequest}`,
143+
);
144+
145+
if (mfaFactorCheck?.redirect) {
146+
console.log("Redirecting to MFA:", mfaFactorCheck.redirect);
147+
const absoluteUrl = constructUrl(request, mfaFactorCheck.redirect);
148+
return NextResponse.redirect(absoluteUrl.toString());
149+
}
150+
}
151+
121152
// if the session is not valid anymore, we need to redirect the user to re-authenticate /
122-
// TODO: handle IDP intent direcly if available
123153
const command: SendLoginnameCommand = {
124154
loginName: selectedSession.factors.user?.loginName,
125155
organization: selectedSession.factors?.user?.organizationId,
@@ -129,8 +159,13 @@ export async function loginWithSAMLAndSession({
129159
const res = await sendLoginname(command);
130160

131161
if (res && "redirect" in res && res?.redirect) {
132-
const absoluteUrl = constructUrl(request, res.redirect);
133-
return NextResponse.redirect(absoluteUrl.toString());
162+
// Check if the redirect URL is already a full URL
163+
if (res.redirect.startsWith("http://") || res.redirect.startsWith("https://")) {
164+
return NextResponse.redirect(res.redirect);
165+
} else {
166+
const absoluteUrl = constructUrl(request, res.redirect);
167+
return NextResponse.redirect(absoluteUrl.toString());
168+
}
134169
}
135170
}
136171

0 commit comments

Comments
 (0)