From ffac1ade3b429a6293c09402334c1071fdcb86b7 Mon Sep 17 00:00:00 2001 From: Ibrahim Nada - Desktop Date: Fri, 8 May 2026 11:04:39 +0300 Subject: [PATCH 1/4] adding RedirectUriPrefix --- .../Elsa.Studio.Login/Models/OpenIdConnectConfiguration.cs | 5 +++++ .../Services/OpenIdConnectAuthorizationService.cs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/modules/Elsa.Studio.Login/Models/OpenIdConnectConfiguration.cs b/src/modules/Elsa.Studio.Login/Models/OpenIdConnectConfiguration.cs index 509a0ad4f..9ee22988a 100644 --- a/src/modules/Elsa.Studio.Login/Models/OpenIdConnectConfiguration.cs +++ b/src/modules/Elsa.Studio.Login/Models/OpenIdConnectConfiguration.cs @@ -20,6 +20,11 @@ public class OpenIdConnectConfiguration /// public required string EndSessionEndpoint { get; set; } + /// + /// A Prefix that can be set before the redirect_uri when sending the authorization request. This is useful in cases where the IdP requires a specific prefix or format for the redirect_uri, such as "https://myapp.com{/workflow}/signin-oidc" instead of just "/signin-oidc". If not set, the redirect_uri will default to the base address of the application plus "/signin-oidc". + /// + public string? RedirectUriPrefix { get; set; } + /// /// The client_id as which this application is registered with the authorization server /// diff --git a/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs b/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs index 1c09e3f84..b7ffd7d95 100644 --- a/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs +++ b/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs @@ -21,7 +21,7 @@ public class OpenIdConnectAuthorizationService(IJwtAccessor jwtAccessor, IOption public async Task RedirectToAuthorizationServer() { var config = configuration.Value; - var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + "/signin-oidc"; + var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + (config.RedirectUriPrefix ?? "") + "/signin-oidc"; string url = config.AuthEndpoint + $"?client_id={WebUtility.UrlEncode(config.ClientId)}&redirect_uri={WebUtility.UrlEncode(redirectUri)}&response_type=code&scope={WebUtility.UrlEncode(String.Join(' ', config.Scopes))}"; if (config.UsePkce) { From 910f72a479fe5b05aeb1e4cda40227613294a962 Mon Sep 17 00:00:00 2001 From: Ibrahim Nada - Desktop Date: Fri, 8 May 2026 11:13:23 +0300 Subject: [PATCH 2/4] addingt (config.RedirectUriPrefix ?? "") to ReceiveAuthorizationCode --- .../Services/OpenIdConnectAuthorizationService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs b/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs index b7ffd7d95..e8dbfcbfb 100644 --- a/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs +++ b/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs @@ -40,7 +40,7 @@ public async Task RedirectToAuthorizationServer() public async Task ReceiveAuthorizationCode(string code, string? state, CancellationToken cancellationToken) { var config = configuration.Value; - var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + "/signin-oidc"; + var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + (config.RedirectUriPrefix ?? "") + "/signin-oidc"; var formValues = new List> { From 577bb8b189ca1d16e228584e7b86176a343de149 Mon Sep 17 00:00:00 2001 From: Ibrahim Nada - Desktop Date: Fri, 8 May 2026 11:13:50 +0300 Subject: [PATCH 3/4] remove space --- .../Services/OpenIdConnectAuthorizationService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs b/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs index e8dbfcbfb..aa57f3703 100644 --- a/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs +++ b/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs @@ -40,7 +40,7 @@ public async Task RedirectToAuthorizationServer() public async Task ReceiveAuthorizationCode(string code, string? state, CancellationToken cancellationToken) { var config = configuration.Value; - var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + (config.RedirectUriPrefix ?? "") + "/signin-oidc"; + var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + (config.RedirectUriPrefix ?? "") + "/signin-oidc"; var formValues = new List> { From 0572c9c8c588d6a449ae98b45857dcbde92173fe Mon Sep 17 00:00:00 2001 From: Ibrahim Nada - Desktop Date: Fri, 8 May 2026 11:32:12 +0300 Subject: [PATCH 4/4] fix greptile-apps notes --- .../Extensions/StringExtensions.cs | 29 +++++++++++++++++++ .../Models/OpenIdConnectConfiguration.cs | 5 +++- .../OpenIdConnectAuthorizationService.cs | 12 ++++---- 3 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 src/modules/Elsa.Studio.Login/Extensions/StringExtensions.cs diff --git a/src/modules/Elsa.Studio.Login/Extensions/StringExtensions.cs b/src/modules/Elsa.Studio.Login/Extensions/StringExtensions.cs new file mode 100644 index 000000000..d064c22fc --- /dev/null +++ b/src/modules/Elsa.Studio.Login/Extensions/StringExtensions.cs @@ -0,0 +1,29 @@ +namespace Elsa.Studio.Login.Extensions; + +/// +/// Provides a set of extension methods for . +/// +internal static class StringExtensions +{ + /// + /// Ensures the string starts with the specified character when non-empty. + /// + public static string EnsureStartsWith(this string? value, string prefix) + { + if (string.IsNullOrEmpty(value)) + return string.Empty; + + return value.StartsWith(prefix) ? value : prefix + value; + } + + /// + /// Ensures the string ends with the specified string when non-empty. + /// + public static string EnsureEndsWith(this string? value, string suffix) + { + if (string.IsNullOrEmpty(value)) + return string.Empty; + + return value.EndsWith(suffix) ? value : value + suffix; + } +} diff --git a/src/modules/Elsa.Studio.Login/Models/OpenIdConnectConfiguration.cs b/src/modules/Elsa.Studio.Login/Models/OpenIdConnectConfiguration.cs index 9ee22988a..741c14056 100644 --- a/src/modules/Elsa.Studio.Login/Models/OpenIdConnectConfiguration.cs +++ b/src/modules/Elsa.Studio.Login/Models/OpenIdConnectConfiguration.cs @@ -21,7 +21,10 @@ public class OpenIdConnectConfiguration public required string EndSessionEndpoint { get; set; } /// - /// A Prefix that can be set before the redirect_uri when sending the authorization request. This is useful in cases where the IdP requires a specific prefix or format for the redirect_uri, such as "https://myapp.com{/workflow}/signin-oidc" instead of just "/signin-oidc". If not set, the redirect_uri will default to the base address of the application plus "/signin-oidc". + /// A prefix to insert before /signin-oidc when constructing the redirect_uri for the authorization request. + /// Useful for sub-path deployments behind a reverse proxy, e.g. setting this to /workflow produces + /// https://myapp.com/workflow/signin-oidc. The value must start with /. When not set the redirect_uri + /// defaults to {origin}/signin-oidc. /// public string? RedirectUriPrefix { get; set; } diff --git a/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs b/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs index aa57f3703..579edaef4 100644 --- a/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs +++ b/src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs @@ -1,4 +1,5 @@ -using Elsa.Studio.Login.Contracts; +using Elsa.Studio.Login.Contracts; +using Elsa.Studio.Login.Extensions; using Elsa.Studio.Login.Models; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.WebUtilities; @@ -21,7 +22,7 @@ public class OpenIdConnectAuthorizationService(IJwtAccessor jwtAccessor, IOption public async Task RedirectToAuthorizationServer() { var config = configuration.Value; - var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + (config.RedirectUriPrefix ?? "") + "/signin-oidc"; + var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + config.RedirectUriPrefix.EnsureStartsWith("/") + "/signin-oidc"; string url = config.AuthEndpoint + $"?client_id={WebUtility.UrlEncode(config.ClientId)}&redirect_uri={WebUtility.UrlEncode(redirectUri)}&response_type=code&scope={WebUtility.UrlEncode(String.Join(' ', config.Scopes))}"; if (config.UsePkce) { @@ -40,7 +41,7 @@ public async Task RedirectToAuthorizationServer() public async Task ReceiveAuthorizationCode(string code, string? state, CancellationToken cancellationToken) { var config = configuration.Value; - var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + (config.RedirectUriPrefix ?? "") + "/signin-oidc"; + var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + config.RedirectUriPrefix.EnsureStartsWith("/") + "/signin-oidc"; var formValues = new List> { @@ -50,7 +51,7 @@ public async Task ReceiveAuthorizationCode(string code, string? state, Cancellat new("redirect_uri", redirectUri) }; - if(!string.IsNullOrWhiteSpace(config.ClientSecret)) + if (!string.IsNullOrWhiteSpace(config.ClientSecret)) { formValues.Add(new KeyValuePair("client_secret", config.ClientSecret)); } @@ -132,7 +133,7 @@ private static async Task ReadErrorSummaryAsync(HttpContent content, Can if (summary.Length > MaxLoggedErrorLength) summary = summary[..MaxLoggedErrorLength]; - return truncated ? $"{summary}…" : summary; + return truncated ? $"{summary}…" : summary; } private static async Task<(string Content, bool Truncated)> ReadContentSnippetAsync(HttpContent content, CancellationToken cancellationToken) @@ -178,4 +179,5 @@ private static async Task ReadErrorSummaryAsync(HttpContent content, Can return null; } + }