diff --git a/src/designer/elsa-workflows-studio/src/modules/credential-manager/models/secrets/oauth2.secret.ts b/src/designer/elsa-workflows-studio/src/modules/credential-manager/models/secrets/oauth2.secret.ts index f39b4ee40b..c87ee264bd 100644 --- a/src/designer/elsa-workflows-studio/src/modules/credential-manager/models/secrets/oauth2.secret.ts +++ b/src/designer/elsa-workflows-studio/src/modules/credential-manager/models/secrets/oauth2.secret.ts @@ -74,17 +74,41 @@ export const OAuth2: Secret = { type: 'System.String', uiHint: 'single-line', }, + { + disableWorkflowProviderSelection: false, + isBrowsable: true, + isReadOnly: false, + label: 'Token endpoint client authentication method', + name: 'ClientAuthMethod', + order: 4, + supportedSyntaxes: ['Literal'], + type: 'System.String', + uiHint: 'dropdown', + options: { + isFlagsEnum: false, + items: [ + { + text: 'Client secret: Basic', + value: 'client_secret_basic', + }, + { + text: 'Client secret: Post', + value: 'client_secret_post', + } + ] + } + }, { disableWorkflowProviderSelection: false, isBrowsable: true, isReadOnly: false, label: 'Scope', name: 'Scope', - order: 4, + order: 5, supportedSyntaxes: ['Literal'], type: 'System.String', uiHint: 'single-line', - }, + } ], type: 'OAuth2', }; diff --git a/src/modules/secrets/Elsa.Secrets.Http/Services/OAuth2TokenService.cs b/src/modules/secrets/Elsa.Secrets.Http/Services/OAuth2TokenService.cs index 33ae2a8555..b37843cfba 100644 --- a/src/modules/secrets/Elsa.Secrets.Http/Services/OAuth2TokenService.cs +++ b/src/modules/secrets/Elsa.Secrets.Http/Services/OAuth2TokenService.cs @@ -43,14 +43,20 @@ public async Task GetToken(Secret secret, string? authCode, strin { var clientId = secret.GetProperty("ClientId"); var clientSecret = secret.GetProperty("ClientSecret"); + var clientAuthMethod = secret.GetProperty("ClientAuthMethod") ?? "client_secret_basic"; var content = new Dictionary { - { "grant_type", secret.GetProperty("GrantType") }, - { "client_id", clientId }, - { "client_secret", clientSecret }, - { "offline_access ", "true" } + { "grant_type", secret.GetProperty("GrantType") } }; + if (clientAuthMethod == "client_secret_post") + { + content.Add("client_id", clientId); + if (!string.IsNullOrEmpty(clientSecret)) + { + content.Add("client_secret", clientSecret); + } + } if (authCode != null) { content.Add("code", authCode); @@ -67,6 +73,10 @@ public async Task GetToken(Secret secret, string? authCode, strin { var httpClient = _httpClientFactory.CreateClient(nameof(OAuth2TokenService)); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + if (clientAuthMethod == "client_secret_basic") + { + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", GenerateAuthorizationValue(clientId, clientSecret)); + } var response = await httpClient.PostAsync(secret.GetProperty("AccessTokenUrl"), new FormUrlEncodedContent(content)); var json = await response.Content.ReadAsStringAsync(); @@ -92,17 +102,28 @@ public async Task GetToken(Secret secret, string? authCode, strin public async Task GetTokenByRefreshToken(Secret secret, string refreshToken) { + var clientId = secret.GetProperty("ClientId"); + var clientSecret = secret.GetProperty("ClientSecret"); + var clientAuthMethod = secret.GetProperty("ClientAuthMethod") ?? "client_secret_basic"; var content = new Dictionary { { "grant_type", "refresh_token" }, - { "client_id", secret.GetProperty("ClientId") }, - { "client_secret", secret.GetProperty("ClientSecret") }, { "refresh_token", refreshToken } }; + + if (clientAuthMethod == "client_secret_post") + { + content.Add("client_id", clientId); + content.Add("client_secret", clientSecret); + } try { var httpClient = _httpClientFactory.CreateClient(nameof(OAuth2TokenService)); + if (clientAuthMethod == "client_secret_basic") + { + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", GenerateAuthorizationValue(clientId, clientSecret)); + } var response = await httpClient.PostAsync(secret.GetProperty("AccessTokenUrl"), new FormUrlEncodedContent(content)); var json = await response.Content.ReadAsStringAsync(); var result = JsonConvert.DeserializeObject(json); @@ -135,4 +156,14 @@ public async Task GetTokenByRefreshToken(Secret secret, string re throw; } } + + private static string GenerateAuthorizationValue(string clientId, string clientSecret) + { + var auth = Uri.EscapeDataString(clientId).Replace("%20", "+"); + if (!string.IsNullOrEmpty(clientSecret)) + { + auth += $":{Uri.EscapeDataString(clientSecret).Replace("%20", "+")}"; + } + return Base64Encode(auth); + } } \ No newline at end of file