mirror of
https://github.com/n8n-io/n8n.git
synced 2026-06-19 07:36:52 +00:00
feat: Force Microsoft account selection on OAuth for all Microsoft credentials (#32015)
This commit is contained in:
@@ -1877,6 +1877,88 @@ describe('OauthService', () => {
|
||||
expect(mockGetUri).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should merge authQueryParameters into the authorize URL query', async () => {
|
||||
const { ClientOAuth2 } = await import('@n8n/client-oauth2');
|
||||
|
||||
// Capture the options passed into the ClientOAuth2 constructor to prove the service
|
||||
// parses authQueryParameters and sets oAuthOptions.query from it.
|
||||
let capturedOptions: { query?: Record<string, string> } | undefined;
|
||||
jest.mocked(ClientOAuth2).mockImplementation((options) => {
|
||||
capturedOptions = options as { query?: Record<string, string> };
|
||||
return {
|
||||
code: {
|
||||
getUri: () => ({
|
||||
toString: () => 'https://example.domain/oauth2/auth?response_type=code',
|
||||
}),
|
||||
},
|
||||
} as any;
|
||||
});
|
||||
|
||||
const credential = mock<CredentialsEntity>({ id: '1', type: 'microsoftOutlookOAuth2Api' });
|
||||
const oauthCredentials: OAuth2CredentialData = {
|
||||
clientId: 'client_id',
|
||||
clientSecret: 'client_secret',
|
||||
authUrl: 'https://example.domain/oauth2/auth',
|
||||
accessTokenUrl: 'https://example.domain/oauth2/token',
|
||||
scope: 'openid',
|
||||
grantType: 'authorizationCode',
|
||||
authentication: 'header',
|
||||
authQueryParameters: 'response_mode=query&prompt=select_account',
|
||||
};
|
||||
|
||||
jest.spyOn(service, 'getOAuthCredentials').mockResolvedValue(oauthCredentials);
|
||||
jest.spyOn(service, 'encryptAndSaveData').mockResolvedValue(undefined);
|
||||
|
||||
await service.generateAOauth2AuthUri(credential, {
|
||||
cid: credential.id,
|
||||
origin: 'static-credential',
|
||||
userId: 'user-id',
|
||||
});
|
||||
|
||||
expect(capturedOptions?.query).toEqual({
|
||||
response_mode: 'query',
|
||||
prompt: 'select_account',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not set query when credentials have no authQueryParameters', async () => {
|
||||
const { ClientOAuth2 } = await import('@n8n/client-oauth2');
|
||||
|
||||
let capturedOptions: { query?: Record<string, string> } | undefined;
|
||||
jest.mocked(ClientOAuth2).mockImplementation((options) => {
|
||||
capturedOptions = options as { query?: Record<string, string> };
|
||||
return {
|
||||
code: {
|
||||
getUri: () => ({
|
||||
toString: () => 'https://example.domain/oauth2/auth?response_type=code',
|
||||
}),
|
||||
},
|
||||
} as any;
|
||||
});
|
||||
|
||||
const credential = mock<CredentialsEntity>({ id: '1', type: 'microsoftOutlookOAuth2Api' });
|
||||
const oauthCredentials: OAuth2CredentialData = {
|
||||
clientId: 'client_id',
|
||||
clientSecret: 'client_secret',
|
||||
authUrl: 'https://example.domain/oauth2/auth',
|
||||
accessTokenUrl: 'https://example.domain/oauth2/token',
|
||||
scope: 'openid',
|
||||
grantType: 'authorizationCode',
|
||||
authentication: 'header',
|
||||
};
|
||||
|
||||
jest.spyOn(service, 'getOAuthCredentials').mockResolvedValue(oauthCredentials);
|
||||
jest.spyOn(service, 'encryptAndSaveData').mockResolvedValue(undefined);
|
||||
|
||||
await service.generateAOauth2AuthUri(credential, {
|
||||
cid: credential.id,
|
||||
origin: 'static-credential',
|
||||
userId: 'user-id',
|
||||
});
|
||||
|
||||
expect(capturedOptions?.query).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle dynamic client registration with root-level server URL', async () => {
|
||||
const axios = require('axios');
|
||||
const { ClientOAuth2 } = await import('@n8n/client-oauth2');
|
||||
|
||||
@@ -37,7 +37,7 @@ export class MicrosoftOAuth2Api implements ICredentialType {
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: 'response_mode=query',
|
||||
default: 'response_mode=query&prompt=select_account',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { MicrosoftOAuth2Api } from '../MicrosoftOAuth2Api.credentials';
|
||||
|
||||
describe('MicrosoftOAuth2Api Credential', () => {
|
||||
const microsoftOAuth2Api = new MicrosoftOAuth2Api();
|
||||
|
||||
it('should have correct credential metadata', () => {
|
||||
expect(microsoftOAuth2Api.name).toBe('microsoftOAuth2Api');
|
||||
expect(microsoftOAuth2Api.displayName).toBe('Microsoft OAuth2 API');
|
||||
expect(microsoftOAuth2Api.extends).toEqual(['oAuth2Api']);
|
||||
|
||||
const authUrlProperty = microsoftOAuth2Api.properties.find((p) => p.name === 'authUrl');
|
||||
expect(authUrlProperty?.default).toBe(
|
||||
'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
|
||||
);
|
||||
|
||||
const accessTokenUrlProperty = microsoftOAuth2Api.properties.find(
|
||||
(p) => p.name === 'accessTokenUrl',
|
||||
);
|
||||
expect(accessTokenUrlProperty?.default).toBe(
|
||||
'https://login.microsoftonline.com/common/oauth2/v2.0/token',
|
||||
);
|
||||
});
|
||||
|
||||
it('should request the Microsoft account chooser via authQueryParameters', () => {
|
||||
const authQueryParamsProperty = microsoftOAuth2Api.properties.find(
|
||||
(p) => p.name === 'authQueryParameters',
|
||||
);
|
||||
expect(authQueryParamsProperty?.type).toBe('hidden');
|
||||
expect(authQueryParamsProperty?.default).toBe('response_mode=query&prompt=select_account');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user