mirror of
https://github.com/n8n-io/n8n.git
synced 2026-08-29 01:39:24 +08:00
feat(Strava Node): Allow custom OAuth2 scopes (#29972)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -100,6 +100,7 @@ export const GENERIC_OAUTH2_CREDENTIALS_WITH_EDITABLE_SCOPE = [
|
||||
'microsoftOAuth2Api',
|
||||
'highLevelOAuth2Api',
|
||||
'mcpOAuth2Api',
|
||||
'stravaOAuth2Api',
|
||||
'wordpressOAuth2Api',
|
||||
];
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
const defaultScopes = 'activity:read_all,activity:write';
|
||||
|
||||
export class StravaOAuth2Api implements ICredentialType {
|
||||
name = 'stravaOAuth2Api';
|
||||
|
||||
@@ -30,19 +32,50 @@ export class StravaOAuth2Api implements ICredentialType {
|
||||
default: 'https://www.strava.com/oauth/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: 'activity:read_all,activity:write',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Custom Scopes',
|
||||
name: 'customScopes',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to define custom OAuth2 scopes instead of the defaults',
|
||||
},
|
||||
{
|
||||
displayName:
|
||||
'The default scopes needed for the node to work are already set. If you change these the node may not function correctly.',
|
||||
name: 'customScopesNotice',
|
||||
type: 'notice',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
customScopes: [true],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Enabled Scopes',
|
||||
name: 'enabledScopes',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
customScopes: [true],
|
||||
},
|
||||
},
|
||||
default: defaultScopes,
|
||||
description: 'Comma-separated list of Strava OAuth2 scopes to request',
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: `={{$self["customScopes"] ? $self["enabledScopes"] : "${defaultScopes}"}}`,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { StravaOAuth2Api } from '../StravaOAuth2Api.credentials';
|
||||
|
||||
describe('StravaOAuth2Api Credential', () => {
|
||||
const credential = new StravaOAuth2Api();
|
||||
const defaultScopes = 'activity:read_all,activity:write';
|
||||
|
||||
it('should have correct credential metadata', () => {
|
||||
expect(credential.name).toBe('stravaOAuth2Api');
|
||||
expect(credential.extends).toEqual(['oAuth2Api']);
|
||||
|
||||
const authUrlProperty = credential.properties.find((p) => p.name === 'authUrl');
|
||||
expect(authUrlProperty?.default).toBe('https://www.strava.com/oauth/authorize');
|
||||
|
||||
const accessTokenUrlProperty = credential.properties.find((p) => p.name === 'accessTokenUrl');
|
||||
expect(accessTokenUrlProperty?.default).toBe('https://www.strava.com/oauth/token');
|
||||
});
|
||||
|
||||
it('should use body authentication', () => {
|
||||
const authenticationProperty = credential.properties.find((p) => p.name === 'authentication');
|
||||
expect(authenticationProperty?.type).toBe('hidden');
|
||||
expect(authenticationProperty?.default).toBe('body');
|
||||
});
|
||||
|
||||
it('should have custom scopes toggle defaulting to false', () => {
|
||||
const customScopesProperty = credential.properties.find((p) => p.name === 'customScopes');
|
||||
expect(customScopesProperty?.type).toBe('boolean');
|
||||
expect(customScopesProperty?.default).toBe(false);
|
||||
});
|
||||
|
||||
it('should have enabledScopes defaulting to the current default scope list', () => {
|
||||
const enabledScopesProperty = credential.properties.find((p) => p.name === 'enabledScopes');
|
||||
expect(enabledScopesProperty?.default).toBe(defaultScopes);
|
||||
});
|
||||
|
||||
it('should only show enabledScopes when customScopes is true', () => {
|
||||
const enabledScopesProperty = credential.properties.find((p) => p.name === 'enabledScopes');
|
||||
expect(enabledScopesProperty?.displayOptions?.show?.customScopes).toEqual([true]);
|
||||
});
|
||||
|
||||
it('should use enabledScopes when customScopes is true, otherwise fall back to defaults', () => {
|
||||
const scopeProperty = credential.properties.find((p) => p.name === 'scope');
|
||||
expect(scopeProperty?.type).toBe('hidden');
|
||||
expect(scopeProperty?.default).toBe(
|
||||
`={{$self["customScopes"] ? $self["enabledScopes"] : "${defaultScopes}"}}`,
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user