Skip to content

Commit 4b9f265

Browse files
authored
Merge pull request #45 from datum-cloud/fix/server-side-idp-validation
fix: prevent unauthorized IDP linking via session validation
2 parents f67c130 + ee44fd6 commit 4b9f265

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ You can already use the current state, and extend it with your needs.
7878
- [x] Domain Discovery
7979
- [x] Branding
8080
- OIDC Standard
81-
8281
- [x] Authorization Code Flow with PKCE
8382
- [x] AuthRequest `hintUserId`
8483
- [x] AuthRequest `loginHint`

apps/login/src/app/(main)/(boxed)/idp/[provider]/success/page.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { loginFailed } from "@/components/idps/pages/login-failed";
66
import { loginSuccess } from "@/components/idps/pages/login-success";
77
import { registrationFailed } from "@/components/idps/pages/registration-failed";
88
import { Translated } from "@/components/translated";
9+
import { getMostRecentSessionCookie } from "@/lib/cookies";
910
import { generateRouteMetadata } from "@/lib/metadata";
1011
import { getServiceUrlFromHeaders } from "@/lib/service-url";
1112
import {
@@ -15,6 +16,7 @@ import {
1516
getIDPByID,
1617
getLoginSettings,
1718
getOrgsByDomain,
19+
getSession,
1820
listUsers,
1921
retrieveIDPIntent,
2022
updateHuman,
@@ -266,6 +268,29 @@ export default async function Page(props: {
266268
if (!resolvedUserId) {
267269
return linkingFailed("User context missing");
268270
}
271+
272+
try {
273+
const recentCookie = await getMostRecentSessionCookie();
274+
const { session } = await getSession({
275+
serviceUrl,
276+
sessionId: recentCookie.id,
277+
sessionToken: recentCookie.token,
278+
});
279+
280+
if (session?.factors?.user?.id !== resolvedUserId) {
281+
console.error(
282+
"Security Violation: Attempt to link IDP to different user",
283+
{
284+
sessionUserId: session?.factors?.user?.id,
285+
targetUserId: resolvedUserId,
286+
},
287+
);
288+
return linkingFailed("Access Denied");
289+
}
290+
} catch {
291+
return linkingFailed("Error getting user session");
292+
}
293+
269294
if (!options?.isLinkingAllowed) {
270295
// linking was probably disallowed since the invitation was created
271296
return linkingFailed("Linking is no longer allowed");

0 commit comments

Comments
 (0)