@azure/msal-common
Version:
Microsoft Authentication Library for js
162 lines (149 loc) • 5.73 kB
text/typescript
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { TokenClaims } from "./TokenClaims.js";
/**
* Account object with the following signature:
* - homeAccountId - Home account identifier for this account object
* - environment - Entity which issued the token represented by the domain of the issuer (e.g. login.microsoftonline.com)
* - tenantId - Full tenant or organizational id that this account belongs to
* - username - preferred_username claim of the id_token that represents this account
* - localAccountId - Local, tenant-specific account identifer for this account object, usually used in legacy cases
* - name - Full name for the account, including given name and family name
* - idToken - raw ID token
* - idTokenClaims - Object contains claims from ID token
* - nativeAccountId - The user's native account ID
* - tenantProfiles - Map of tenant profile objects for each tenant that the account has authenticated with in the browser
*/
export type AccountInfo = {
homeAccountId: string;
environment: string;
tenantId: string;
username: string;
localAccountId: string;
name?: string;
idToken?: string;
idTokenClaims?: TokenClaims & {
[key: string]:
| string
| number
| string[]
| object
| undefined
| unknown;
};
nativeAccountId?: string;
authorityType?: string;
tenantProfiles?: Map<string, TenantProfile>;
};
/**
* Account details that vary across tenants for the same user
*/
export type TenantProfile = Pick<
AccountInfo,
"tenantId" | "localAccountId" | "name"
> & {
/**
* - isHomeTenant - True if this is the home tenant profile of the account, false if it's a guest tenant profile
*/
isHomeTenant?: boolean;
};
export type ActiveAccountFilters = {
homeAccountId: string;
localAccountId: string;
tenantId?: string;
};
/**
* Returns true if tenantId matches the utid portion of homeAccountId
* @param tenantId
* @param homeAccountId
* @returns
*/
export function tenantIdMatchesHomeTenant(
tenantId?: string,
homeAccountId?: string
): boolean {
return (
!!tenantId &&
!!homeAccountId &&
tenantId === homeAccountId.split(".")[1]
);
}
/**
* Build tenant profile
* @param homeAccountId - Home account identifier for this account object
* @param localAccountId - Local account identifer for this account object
* @param tenantId - Full tenant or organizational id that this account belongs to
* @param idTokenClaims - Claims from the ID token
* @returns
*/
export function buildTenantProfile(
homeAccountId: string,
localAccountId: string,
tenantId: string,
idTokenClaims?: TokenClaims
): TenantProfile {
if (idTokenClaims) {
const { oid, sub, tid, name, tfp, acr } = idTokenClaims;
/**
* Since there is no way to determine if the authority is AAD or B2C, we exhaust all the possible claims that can serve as tenant ID with the following precedence:
* tid - TenantID claim that identifies the tenant that issued the token in AAD. Expected in all AAD ID tokens, not present in B2C ID Tokens.
* tfp - Trust Framework Policy claim that identifies the policy that was used to authenticate the user. Functions as tenant for B2C scenarios.
* acr - Authentication Context Class Reference claim used only with older B2C policies. Fallback in case tfp is not present, but likely won't be present anyway.
*/
const tenantId = tid || tfp || acr || "";
return {
tenantId: tenantId,
localAccountId: oid || sub || "",
name: name,
isHomeTenant: tenantIdMatchesHomeTenant(tenantId, homeAccountId),
};
} else {
return {
tenantId,
localAccountId,
isHomeTenant: tenantIdMatchesHomeTenant(tenantId, homeAccountId),
};
}
}
/**
* Replaces account info that varies by tenant profile sourced from the ID token claims passed in with the tenant-specific account info
* @param baseAccountInfo
* @param idTokenClaims
* @returns
*/
export function updateAccountTenantProfileData(
baseAccountInfo: AccountInfo,
tenantProfile?: TenantProfile,
idTokenClaims?: TokenClaims,
idTokenSecret?: string
): AccountInfo {
let updatedAccountInfo = baseAccountInfo;
// Tenant Profile overrides passed in account info
if (tenantProfile) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { isHomeTenant, ...tenantProfileOverride } = tenantProfile;
updatedAccountInfo = { ...baseAccountInfo, ...tenantProfileOverride };
}
// ID token claims override passed in account info and tenant profile
if (idTokenClaims) {
// Ignore isHomeTenant, loginHint, and sid which are part of tenant profile but not base account info
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { isHomeTenant, ...claimsSourcedTenantProfile } =
buildTenantProfile(
baseAccountInfo.homeAccountId,
baseAccountInfo.localAccountId,
baseAccountInfo.tenantId,
idTokenClaims
);
updatedAccountInfo = {
...updatedAccountInfo,
...claimsSourcedTenantProfile,
idTokenClaims: idTokenClaims,
idToken: idTokenSecret,
};
return updatedAccountInfo;
}
return updatedAccountInfo;
}