Related questions
Problem
I have a service running under a specific path on a domain, e.g. https://www.example.com/myservice. The myservice path is dedicated to my service and other services have other paths at the same domain. It is setup like this in startup configure:
app.Map("/myservice", builder =>
{
builder.UseStaticFiles();
builder.UseMvcWithDefaultRoute();
});
I am using a library that implements a custom RemoteAuthenticationHandler. By default, the callback path routes to /x-callback which results in the browser trying to access https://www.example.com/x-callback.
Since my service does not process url's without the /myservice prefix I get a 404. Changing the URL in the browser to /myservice/x-callback manually loads the callback and all is fine.
I can set the callback path for the handler in startup options as expected in startup configure services.
services.AddSomething(options =>
{
options.AddThingX((o) =>
{
o.CallbackPath = new PathString($"/myservice{o.CallbackPath}");
});
});
When I set the callback path like that the browser tries to load /myservice/x-callback. But, this URL now returns a 404. It seems the handler for the callback also has its URL changed. Changing the URL in the browser to /myservice/myservice/x-callback loads the callback as expected.
The RemoteAuthenticationHandler
This is the code in the handler that handles the challenge and uses the callback path. It sets the callback path as a query parameter to the login url.
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
{
// Add options etc
// ...
// ...
// This defines the login url, with a query parameter for the CallbackPath
var loginUrl = GetLoginUrl(loginOptions);
Response.Redirect(loginUrl);
return Task.CompletedTask;
}
private string GetLoginUrl(MyServiceLoginOptions loginOptions)
{
// This is where the return url is set. The return url
// is used after login credentials are verified.
return $"{Options.LoginPath}" +
$"?returnUrl={UrlEncoder.Encode(Options.CallbackPath)}" +
$"&loginOptions={UrlEncoder.Encode(_loginOptionsProtector.Protect(loginOptions))}";
}
The login controller
This is where the user can provide the credentials and have them verified. After verification, the user is redirected to the callback path.
private async Task<ActionResult> ChallengeComplete(LoginStatusRequest request, ChallengeResponse challengeResponse)
{
// auth logic
// ...
// All is fine, the users credentials have been verified. Now
// we can redirect to the CallbackPath.
return Ok(Response.Finished(returnUri));
}
Note
I could do a URL rewrite but if possible, I would like to use the "correct" /myservice path to avoid confusion and perhaps causing issues for other services (though very unlikely).
Question
How can I prefix the callback path with /myservice so my application can process it without also adding the duplicate prefix?
MapMiddleware is adding the matched path to the Request.PathBase, so you can use it when creating the return url
string returnUrl = Context.Request.PathBase + Options.CallbackPath;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With