Skip to content

Instantly share code, notes, and snippets.

@TheRealXaiL
Last active June 10, 2025 12:23
Show Gist options
  • Select an option

  • Save TheRealXaiL/823e5c6404fa2f3d8399d9dcfec83966 to your computer and use it in GitHub Desktop.

Select an option

Save TheRealXaiL/823e5c6404fa2f3d8399d9dcfec83966 to your computer and use it in GitHub Desktop.
interface TenantInfo {
tenant_id: string;
tenant_name: string;
tenant_region: string;
cloud_instance: string;
sso_enabled: string;
domain_count: number;
federated_domains?: string[]; // Optional field
}
async function getFederatedDomains(domain: string): Promise<{ count: number; domains: string[] }> {
const autodiscoverPostBody = `<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:exm="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:ext="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<a:Action soap:mustUnderstand="1">http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation</a:Action>
<a:To soap:mustUnderstand="1">https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc</a:To>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
</soap:Header>
<soap:Body>
<GetFederationInformationRequestMessage xmlns="http://schemas.microsoft.com/exchange/2010/Autodiscover">
<Request>
<Domain>${domain}</Domain>
</Request>
</GetFederationInformationRequestMessage>
</soap:Body>
</soap:Envelope>`;
const autodiscoverPostHeaders = {
"Content-Type": "text/xml; charset=utf-8",
"SOAPAction": '"http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation"',
"User-Agent": "AutodiscoverClient"
};
try {
const response = await fetch('https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc', {
method: 'POST',
headers: autodiscoverPostHeaders,
body: autodiscoverPostBody,
});
if (!response.ok) {
return { count: 0, domains: [] };
}
const text = await response.text();
// Extract domain names from XML response
const domainMatches = text.match(/<Domain>([^<]+)<\/Domain>/g) || [];
const domains = domainMatches.map(match =>
match.replace(/<Domain>|<\/Domain>/g, '')
);
return {
count: domains.length,
domains: domains
};
} catch (error) {
return { count: 0, domains: [] };
}
}
async function getTenantInfo(domain: string, includeDomains: boolean = false): Promise<TenantInfo | null> {
const url = `https://login.microsoftonline.com/${domain}/.well-known/openid-configuration`;
try {
const response = await fetch(url);
if (!response.ok) {
return null;
}
const tenantInfo = await response.json();
const issuer = tenantInfo.issuer || "";
const tenantId = issuer.split('/').slice(-2)[0] || "Unknown";
const federatedInfo = await getFederatedDomains(domain);
const result: TenantInfo = {
tenant_id: tenantId,
tenant_name: domain,
tenant_region: tenantInfo.tenant_region_scope || "Unknown",
cloud_instance: tenantInfo.cloud_instance_name || "Unknown",
sso_enabled: tenantInfo.frontchannel_logout_supported ? "Yes" : "No",
domain_count: federatedInfo.count
};
// Only include federated_domains if explicitly requested
if (includeDomains) {
result.federated_domains = federatedInfo.domains;
}
return result;
} catch (error) {
return null;
}
}
export default {
async fetch(request: Request): Promise<Response> {
// Handle CORS preflight requests
if (request.method === "OPTIONS") {
return new Response(null, {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET",
"Access-Control-Allow-Headers": "Content-Type",
},
});
}
// Only allow GET requests
if (request.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
const url = new URL(request.url);
const domain = url.pathname.split("/").pop();
if (!domain) {
return new Response(JSON.stringify({
error: "Domain parameter is required"
}), {
status: 400,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
});
}
// Check if domains should be included based on GET parameter
const includeDomains = url.searchParams.has('domains') || url.searchParams.get('domains') === 'true';
const tenantInfo = await getTenantInfo(domain, includeDomains);
if (!tenantInfo) {
return new Response(JSON.stringify({
error: "Unable to fetch tenant information",
domain: domain
}), {
status: 404,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
});
}
return new Response(JSON.stringify(tenantInfo), {
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
});
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment