fix: improve auth step to avoid takeovers

This commit is contained in:
Daniel Hougaard
2025-05-01 04:08:58 +04:00
parent aedc6e16ad
commit e08c5f265e
10 changed files with 109 additions and 53 deletions
@@ -59,6 +59,7 @@ export type TUpdateMicrosoftTeamsIntegrationDTO = {
};
export type TCreateMicrosoftTeamsIntegrationDTO = {
code: string;
tenantId: string;
slug: string;
description?: string;
@@ -1,3 +1,5 @@
import crypto from "crypto";
import { useCallback, useEffect, useState } from "react";
import { useNavigate, useSearch } from "@tanstack/react-router";
import { z } from "zod";
@@ -13,7 +15,8 @@ const stateSchema = z.object({
tenantId: z.string(),
slug: z.string(),
description: z.string().optional(),
csrfToken: z.string()
csrfToken: z.string(),
clientId: z.string()
});
export const OAuthCallbackPage = () => {
@@ -27,7 +30,9 @@ export const OAuthCallbackPage = () => {
const createMicrosoftTeamsWorkflowIntegration = useCreateMicrosoftTeamsIntegration();
const { state: rawState, tenant: stateTenant, admin_consent: adminConsent } = search;
const { state: rawState, code } = search;
console.log("the code is ", code);
const state = stateSchema.parse(rawState);
@@ -42,21 +47,29 @@ export const OAuthCallbackPage = () => {
const handleMicrosoftTeams = useCallback(async () => {
clearState();
if (Boolean(adminConsent.toLowerCase()) !== true) {
throw new Error("Failed to grant admin consent");
}
if (stateTenant !== state.tenantId) {
throw new Error(`Invalid tenant ID. Expected ${stateTenant}, got ${state.tenantId}`);
if (!code) {
throw new Error("No code provided");
}
await createMicrosoftTeamsWorkflowIntegration.mutateAsync({
orgId: currentOrg.id,
tenantId: state.tenantId,
code,
slug: state.slug,
description: state.description ?? "",
redirectUri: state.redirectUri
});
createNotification({
text: "Successfully granted Microsoft Teams admin consent",
type: "success"
});
navigate({
to: ROUTE_PATHS.Organization.SettingsPage.path
});
return;
}, []);
// Ensure that the localstorage is ready for use, to avoid the form data being malformed
@@ -72,22 +85,16 @@ export const OAuthCallbackPage = () => {
(async () => {
try {
await handleMicrosoftTeams();
createNotification({
text: "Successfully granted Microsoft Teams admin consent",
type: "success"
});
} catch (err) {
console.error(err);
createNotification({
text: "Failed to grant Microsoft Teams admin consent",
text:
code !== ""
? "Failed to create Microsoft Teams workflow integration"
: "Failed to grant Microsoft Teams admin consent",
type: "error"
});
}
navigate({
to: ROUTE_PATHS.Organization.SettingsPage.path
});
})();
}, [isReady]);
@@ -7,6 +7,7 @@ import { OAuthCallbackPage } from "./OauthCallbackPage";
const SettingsOAuthCallbackPageQueryParamsSchema = z.object({
state: z
.object({
clientId: z.string(),
tenantId: z.string(),
slug: z.string(),
description: z.string().optional(),
@@ -15,8 +16,7 @@ const SettingsOAuthCallbackPageQueryParamsSchema = z.object({
})
.nullable()
.catch(null),
tenant: z.string().catch(""),
admin_consent: z.string().catch("")
code: z.string().catch("")
});
export const Route = createFileRoute(
@@ -103,10 +103,20 @@ export const MicrosoftTeamsIntegrationForm = ({ id, onClose }: Props) => {
tenantId,
slug,
description,
csrfToken
csrfToken,
clientId: microsoftTeamsClientId.clientId
};
const url = `https://login.microsoftonline.com/${tenantId}/adminconsent?client_id=${microsoftTeamsClientId.clientId}&redirect_uri=${state.redirectUri}&state=${encodeURIComponent(JSON.stringify(state))}`;
const url = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize?
client_id=${microsoftTeamsClientId.clientId}
&redirect_uri=${state.redirectUri}
&response_type=code
&response_mode=query
&scope=https://graph.microsoft.com/.default
&state=${encodeURIComponent(JSON.stringify(state))}
&prompt=consent
&admin_consent=true`;
window.location.href = url;
}
};