Path: blob/main/extensions/microsoft-authentication/src/common/scopeData.ts
3320 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { Uri } from 'vscode';67const DEFAULT_CLIENT_ID = 'aebc6443-996d-45c2-90f0-388ff96faa56';8const DEFAULT_TENANT = 'organizations';910const OIDC_SCOPES = ['openid', 'email', 'profile', 'offline_access'];11const GRAPH_TACK_ON_SCOPE = 'User.Read';1213export class ScopeData {14/**15* The full list of scopes including:16* * the original scopes passed to the constructor17* * internal VS Code scopes (e.g. `VSCODE_CLIENT_ID:...`)18* * the default scopes (`openid`, `email`, `profile`, `offline_access`)19*/20readonly allScopes: string[];2122/**23* The full list of scopes as a space-separated string. For logging.24*/25readonly scopeStr: string;2627/**28* The list of scopes to send to the token endpoint. This is the same as `scopes` but without the internal VS Code scopes.29*/30readonly scopesToSend: string[];3132/**33* The client ID to use for the token request. This is the value of the `VSCODE_CLIENT_ID:...` scope if present, otherwise the default client ID.34*/35readonly clientId: string;3637/**38* The tenant ID or `organizations`, `common`, `consumers` to use for the token request. This is the value of the `VSCODE_TENANT:...` scope if present, otherwise it's the default.39*/40readonly tenant: string;4142/**43* The tenant ID to use for the token request. This will only ever be a GUID if one was specified via the `VSCODE_TENANT:...` scope, otherwise undefined.44*/45readonly tenantId: string | undefined;4647/**48* The claims to include in the token request.49*/50readonly claims?: string;5152constructor(readonly originalScopes: readonly string[] = [], claims?: string, authorizationServer?: Uri) {53const modifiedScopes = [...originalScopes];54modifiedScopes.sort();55this.allScopes = modifiedScopes;56this.scopeStr = modifiedScopes.join(' ');57this.claims = claims;58this.scopesToSend = this.getScopesToSend(modifiedScopes);59this.clientId = this.getClientId(this.allScopes);60this.tenant = this.getTenant(this.allScopes, authorizationServer);61this.tenantId = this.getTenantId(this.tenant);62}6364private getClientId(scopes: string[]): string {65return scopes.reduce<string | undefined>((prev, current) => {66if (current.startsWith('VSCODE_CLIENT_ID:')) {67return current.split('VSCODE_CLIENT_ID:')[1];68}69return prev;70}, undefined) ?? DEFAULT_CLIENT_ID;71}7273private getTenant(scopes: string[], authorizationServer?: Uri): string {74if (authorizationServer?.path) {75// Get tenant portion of URL76const tenant = authorizationServer.path.split('/')[1];77if (tenant) {78return tenant;79}80}81return scopes.reduce<string | undefined>((prev, current) => {82if (current.startsWith('VSCODE_TENANT:')) {83return current.split('VSCODE_TENANT:')[1];84}85return prev;86}, undefined) ?? DEFAULT_TENANT;87}8889private getTenantId(tenant: string): string | undefined {90switch (tenant) {91case 'organizations':92case 'common':93case 'consumers':94// These are not valid tenant IDs, so we return undefined95return undefined;96default:97return this.tenant;98}99}100101private getScopesToSend(scopes: string[]): string[] {102const scopesToSend = scopes.filter(s => !s.startsWith('VSCODE_'));103104const set = new Set(scopesToSend);105for (const scope of OIDC_SCOPES) {106set.delete(scope);107}108109// If we only had OIDC scopes, we need to add a tack-on scope to make the request valid110// by forcing Identity into treating this as a Graph token request.111if (!set.size) {112scopesToSend.push(GRAPH_TACK_ON_SCOPE);113}114return scopesToSend;115}116}117118119