Skip to content

Commit dfc1e49

Browse files
authored
[Identity] DeviceCodeCredential constructor unification (Azure#14443)
DeviceCodeCredential stopped having required parameters a while ago, when we started completing the values for tenant ID and client ID by default. However, even though our guidelines establish that we should group all of the optional parameters in option bags, the signature of this constructor never changed. As part of my recent Identity changes, I've made it so the DeviceCodeCredential constructor could also accept only receiving the optional parameters. The intention there was to not do a breaking change initially, but since we're targeting a major version release, having this constructor overload feels unnecessary. This PR makes it so DeviceCodeCredential only accepts an options bag as the first parameter, without overloads. While doing these changes, I was able to spot a bug I introduced in my recent changes (currently on master, but not released) by which clientId and tenantId were not properly passed through if sent only through the options bag. While this is fixed by this PR too, that fix caused the recordings not to match, as some of the recordings were using the default values for clientId and tenantId instead of the ones passed through. I've fixed the tests to match what the recordings represented, which essentially allows us to test that the default values for tenantId and clientId can work, meaning that now I'm treating the device code tests as if sometimes used the default parameters. Fixes: Azure#14420
1 parent cd3557a commit dfc1e49

File tree

5 files changed

+26
-52
lines changed

5 files changed

+26
-52
lines changed

sdk/identity/identity/review/identity.api.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ export function deserializeAuthenticationRecord(serializedRecord: string): Authe
126126
// @public
127127
export class DeviceCodeCredential implements TokenCredential {
128128
constructor(options?: DeviceCodeCredentialOptions);
129-
constructor(tenantId?: string, clientId?: string, userPromptCallback?: DeviceCodePromptCallback, options?: DeviceCodeCredentialOptions);
130129
authenticate(scopes: string | string[], options?: GetTokenOptions): Promise<AuthenticationRecord | undefined>;
131130
getToken(scopes: string | string[], options?: GetTokenOptions): Promise<AccessToken>;
132131
}

sdk/identity/identity/src/credentials/deviceCodeCredential.ts

Lines changed: 3 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ import { MsalDeviceCode } from "../msal/nodeFlows/msalDeviceCode";
77
import { MsalFlow } from "../msal/flows";
88
import { AuthenticationRecord } from "../msal/types";
99
import { trace } from "../util/tracing";
10-
import {
11-
DeviceCodeCredentialOptions,
12-
DeviceCodeInfo,
13-
DeviceCodePromptCallback
14-
} from "./deviceCodeCredentialOptions";
10+
import { DeviceCodeCredentialOptions, DeviceCodeInfo } from "./deviceCodeCredentialOptions";
1511

1612
const logger = credentialLogger("DeviceCodeCredential");
1713

@@ -35,41 +31,13 @@ export class DeviceCodeCredential implements TokenCredential {
3531
* Creates an instance of DeviceCodeCredential with the details needed
3632
* to initiate the device code authorization flow with Azure Active Directory.
3733
*
38-
* @param tenantId - The Azure Active Directory tenant (directory) ID or name.
39-
* The default value is 'organizations'.
40-
* 'organizations' may be used when dealing with multi-tenant scenarios.
41-
* Users can also pass the options as the first parameter, and skip the other parammeters entirely.
42-
* @param clientId - The client (application) ID of an App Registration in the tenant.
43-
* By default we will try to use the Azure CLI's client ID to authenticate.
44-
* @param userPromptCallback - A callback function that will be invoked to show
45-
* {@link DeviceCodeInfo} to the user. If left unassigned, we will automatically log the device code information and the authentication instructions in the console.
4634
* @param options - Options for configuring the client which makes the authentication requests.
4735
*/
48-
constructor(options?: DeviceCodeCredentialOptions);
49-
constructor(
50-
tenantId?: string,
51-
clientId?: string,
52-
userPromptCallback?: DeviceCodePromptCallback,
53-
options?: DeviceCodeCredentialOptions
54-
);
55-
constructor(
56-
tenantIdOrOptions?: string | DeviceCodeCredentialOptions,
57-
clientId?: string,
58-
userPromptCallback?: DeviceCodePromptCallback,
59-
options?: DeviceCodeCredentialOptions
60-
) {
61-
let tenantId: string | undefined;
62-
if (typeof tenantIdOrOptions === "string") {
63-
tenantId = tenantIdOrOptions;
64-
} else {
65-
options = tenantIdOrOptions;
66-
}
36+
constructor(options?: DeviceCodeCredentialOptions) {
6737
this.msalFlow = new MsalDeviceCode({
6838
...options,
6939
logger,
70-
clientId,
71-
tenantId,
72-
userPromptCallback: userPromptCallback || defaultDeviceCodePromptCallback,
40+
userPromptCallback: options?.userPromptCallback || defaultDeviceCodePromptCallback,
7341
tokenCredentialOptions: options || {}
7442
});
7543
this.disableAutomaticAuthentication = options?.disableAutomaticAuthentication;

sdk/identity/identity/test/internal/identityClient.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,9 @@ describe("IdentityClient", function() {
7777
);
7878
});
7979

80-
it("throws an exception when an Env AZURE_AUTHORITY_HOST using 'http' is provided", /** @this Mocha.Context */ async function() {
80+
it("throws an exception when an Env AZURE_AUTHORITY_HOST using 'http' is provided", async function() {
8181
if (!isNode) {
82+
// eslint-disable-next-line no-invalid-this
8283
return this.skip();
8384
}
8485
process.env.AZURE_AUTHORITY_HOST = "http://totallyinsecure.lol";

sdk/identity/identity/test/internal/node/deviceCodeCredential.spec.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ describe("DeviceCodeCredential (internal)", function() {
4141
if (isLiveMode()) {
4242
this.skip();
4343
}
44-
const credential = new DeviceCodeCredential(env.AZURE_TENANT_ID, env.AZURE_CLIENT_ID);
44+
const credential = new DeviceCodeCredential({
45+
tenantId: env.AZURE_TENANT_ID,
46+
clientId: env.AZURE_CLIENT_ID
47+
});
4548

4649
await credential.getToken(scope);
4750
assert.equal(getTokenSilentSpy.callCount, 1);
@@ -77,8 +80,6 @@ describe("DeviceCodeCredential (internal)", function() {
7780
persistence?.save("");
7881

7982
const credential = new DeviceCodeCredential({
80-
tenantId: env.AZURE_TENANT_ID,
81-
clientId: env.AZURE_CLIENT_ID,
8283
tokenCachePersistenceOptions
8384
});
8485

@@ -113,8 +114,6 @@ describe("DeviceCodeCredential (internal)", function() {
113114
persistence?.save("");
114115

115116
const credential = new DeviceCodeCredential({
116-
tenantId: env.AZURE_TENANT_ID,
117-
clientId: env.AZURE_CLIENT_ID,
118117
tokenCachePersistenceOptions
119118
});
120119

@@ -156,8 +155,6 @@ describe("DeviceCodeCredential (internal)", function() {
156155
persistence?.save("");
157156

158157
const credential = new DeviceCodeCredential({
159-
tenantId: env.AZURE_TENANT_ID,
160-
clientId: env.AZURE_CLIENT_ID,
161158
// To be able to re-use the account, the Token Cache must also have been provided.
162159
// TODO: Perhaps make the account parameter part of the tokenCachePersistenceOptions?
163160
tokenCachePersistenceOptions
@@ -169,8 +166,6 @@ describe("DeviceCodeCredential (internal)", function() {
169166
assert.equal(doGetTokenSpy.callCount, 1);
170167

171168
const credential2 = new DeviceCodeCredential({
172-
tenantId: env.AZURE_TENANT_ID,
173-
clientId: env.AZURE_CLIENT_ID,
174169
authenticationRecord: account,
175170
// To be able to re-use the account, the Token Cache must also have been provided.
176171
// TODO: Perhaps make the account parameter part of the tokenCachePersistenceOptions?

sdk/identity/identity/test/public/node/deviceCodeCredential.spec.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ describe("DeviceCodeCredential", function() {
3737
if (isLiveMode()) {
3838
this.skip();
3939
}
40-
const credential = new DeviceCodeCredential(env.AZURE_TENANT_ID, env.AZURE_CLIENT_ID);
40+
const credential = new DeviceCodeCredential({
41+
tenantId: env.AZURE_TENANT_ID,
42+
clientId: env.AZURE_CLIENT_ID
43+
});
4144

4245
const token = await credential.getToken(scope);
4346
assert.ok(token?.token);
@@ -52,7 +55,11 @@ describe("DeviceCodeCredential", function() {
5255
const callback: DeviceCodePromptCallback = (info) => {
5356
console.log("CUSTOMIZED PROMPT CALLBACK", info.message);
5457
};
55-
const credential = new DeviceCodeCredential(env.AZURE_TENANT_ID, env.AZURE_CLIENT_ID, callback);
58+
const credential = new DeviceCodeCredential({
59+
tenantId: env.AZURE_TENANT_ID,
60+
clientId: env.AZURE_CLIENT_ID,
61+
userPromptCallback: callback
62+
});
5663

5764
const token = await credential.getToken(scope);
5865
assert.ok(token?.token);
@@ -61,7 +68,10 @@ describe("DeviceCodeCredential", function() {
6168

6269
// Setting the MSAL options to cancel doesn't seem to be cancelling MSAL. I'm waiting for them to mention how to do this.
6370
it.skip("allows cancelling the authentication", async function() {
64-
const credential = new DeviceCodeCredential(env.AZURE_TENANT_ID, env.AZURE_CLIENT_ID);
71+
const credential = new DeviceCodeCredential({
72+
tenantId: env.AZURE_TENANT_ID,
73+
clientId: env.AZURE_CLIENT_ID
74+
});
6575

6676
const controller = new AbortController();
6777
const getTokenPromise = credential.getToken(scope, {
@@ -87,8 +97,6 @@ describe("DeviceCodeCredential", function() {
8797
this.skip();
8898
}
8999
const credential = new DeviceCodeCredential({
90-
tenantId: env.AZURE_TENANT_ID,
91-
clientId: env.AZURE_CLIENT_ID,
92100
disableAutomaticAuthentication: true
93101
});
94102

@@ -114,7 +122,10 @@ describe("DeviceCodeCredential", function() {
114122
}
115123
await testTracing({
116124
test: async (spanOptions) => {
117-
const credential = new DeviceCodeCredential(env.AZURE_TENANT_ID, env.AZURE_CLIENT_ID);
125+
const credential = new DeviceCodeCredential({
126+
tenantId: env.AZURE_TENANT_ID,
127+
clientId: env.AZURE_CLIENT_ID
128+
});
118129

119130
await credential.getToken(scope, {
120131
tracingOptions: {

0 commit comments

Comments
 (0)