3
votes

I have an Identity server using Identity server 4. When a new user registers we send them a conformation email

var callbackUrl = Url.EmailConfirmationLink(user.Id.ToString(), code, Request.Scheme);
            if (_emailSender.SendEmailConfirmation(model.Email, callbackUrl, out var errors))
                return RedirectToAction("CreateUserConfirmation");

The url sent to the user looks like this

http://localhost:5000/Account/ConfirmEmail?userId=21248584&code=CfDJ8Fjc0B4fXChAiNkOxmI4n6Tm8kxBYVt59xoQ7QqEiE8EdPVknVaQaMq7HACmGUGANjSc6LY0OjvWye%2BcZB8J9YMgB84uCsPRTRzno2W%2B1XtHsYD7zn%2FzZSxhCObppyj2ezPbY7O8wa18a0gvfqrHB2jEWjOxX2eauZkvRUvjxYGBIch0dN8A94VgO7qbTssmcsbI3kbSAmAP4a4%2B05iVK2Y%3D&returnUrl=/connect/authorize/callback?client_id=XenaClient&redirect_uri=http%3A%2F%2Flocalhost%3A49000%2Fsignin-oidc&response_mode=form_post&response_type=id_token%20token%20code&scope=openid%20profile%20testapi&state=OpenIdConnect.AuthenticationProperties%3DoJ7JIbKOpJI6pQuFrpY7YmrqyU2x-8TbuBM_d2XOTdZZZAMYW_RXfckkwDI-G88UkChcDlxYKmpba688bTKUt7VMKPz6Js8dQtyE2goLJASrSLmItXbynP0XC4o7DiM9FQQ_HcsB6vtX4tGFNvFfmAascO_ZyUZM63vHg6ntBBsm4CnbulgqDcECrjFCqpafiqw4gw&nonce=636705184638441890.ZjhkOTIz0NjAtNDRmZS00ODgwLWIwOWQtOWY2YWRkNTMwMTBhYmE4NjQ3MjYtMTllNS00ZWFlLWExMTEtYTRkNzQ2Y2JmYjFm

Redirect back to the application

When the application directs to the Identity server for user login it sends with it a returnurl. This url is used to return the user back to the application after they have logged in

returnurl=/connect/authorize/callback?client_id=XenaClient&redirect_uri=http%3A%2F%2Flocalhost%3A49000%2Fsignin-oidc&response_mode=form_post&response_type=id_token%20token%20code&scope=openid%20profile%20testapi&state=OpenIdConnect.AuthenticationProperties%3Duqw4onaEn-5TgYhVg5nQnRpvZYC1C8y12c5VTheRQlVI5y6GzTzgJCsuPTx_NoPVIFXY2ZSZKbhs4VxQ0HjJik4LGF0E2ToFAFDuonTJC3WwNSlFPN5eTrsbqebms-fqZq7dcpUOjhYU-kLpGcKSyaSXe5qr0EOanqIdEyV9H0EZolq38pjvBJWFf0bWC6KPNCZ4Nw&nonce=636705214204045725.YWI1YmVhNDQtYTE4MC00ZDIwLWJmMDQtYjA3YzNmMGYyODg3ZTNhNTNlMmEtNzQ1YS00M2Y4LWI2N2YtODY4MDg5OGNmYzNj

This works fine with existing users.

Redirect new user

When a new user registers their account the email they are sent does not redirect them back to the application. They are left stuck on the Identity server itself.

Add returnurl to confirm email (What I tried)

What I tried to do was tack the returnurl onto the confirm url email. So that when the user confirms their email they are routed back

 public async Task<IActionResult> ConfirmEmail([FromQuery] string userId, [FromQuery] string code,[FromQuery]  string returnUrl = null)
    {
      ............

     return (returnUrl == null)
            ? RedirectToAction("Login")
            : RedirectToLocal(returnUrl);
    }

The huge url sent in the email looks like this

http://localhost:5000/Account/ConfirmEmail?userId=21248584&code=CfDJ8Fjc0B4fXChAiNkOxmI4n6Tm8kxBYVt59xoQ7QqEiE8EdPVknVaQaMq7HACmGUGANjSc6LY0OjvWye%2BcZB8J9YMgB84uCsPRTRzno2W%2B1XtHsYD7zn%2FzZSxhCObppyj2ezPbY7O8wa18a0gvfqrHB2jEWjOxX2eauZkvRUvjxYGBIch0dN8A94VgO7qbTssmcsbI3kbSAmAP4a4%2B05iVK2Y%3D&returnUrl=/connect/authorize/callback?client_id=XenaClient&redirect_uri=http%3A%2F%2Flocalhost%3A49000%2Fsignin-oidc&response_mode=form_post&response_type=id_token%20token%20code&scope=openid%20profile%20testapi&state=OpenIdConnect.AuthenticationProperties%3DoJ7JIbKOpJI6pQuFrpY7YmrqyU2x-8TbuBM_d2XOTdZZZAMYW_RXfckkwDI-G88UkChcDlxYKmpba688bTKUt7VMKPz6Js8dQtyE2goLJASrSLmItXbynP0XC4o7DiM9FQQ_HcsB6vtX4tGFNvFfmAascO_ZyUZM63vHg6ntBBsm4CnbulgqDcECrjFCqpafiqw4gw&nonce=636705184638441890.ZjhkOTIz0NjAtNDRmZS00ODgwLWIwOWQtOWY2YWRkNTMwMTBhYmE4NjQ3MjYtMTllNS00ZWFlLWExMTEtYTRkNzQ2Y2JmYjFm&returnurl=/connect/authorize/callback?client_id=XenaClient&redirect_uri=http%3A%2F%2Flocalhost%3A49000%2Fsignin-oidc&response_mode=form_post&response_type=id_token%20token%20code&scope=openid%20profile%20testapi&state=OpenIdConnect.AuthenticationProperties%3Duqw4onaEn-5TgYhVg5nQnRpvZYC1C8y12c5VTheRQlVI5y6GzTzgJCsuPTx_NoPVIFXY2ZSZKbhs4VxQ0HjJik4LGF0E2ToFAFDuonTJC3WwNSlFPN5eTrsbqebms-fqZq7dcpUOjhYU-kLpGcKSyaSXe5qr0EOanqIdEyV9H0EZolq38pjvBJWFf0bWC6KPNCZ4Nw&nonce=636705214204045725.YWI1YmVhNDQtYTE4MC00ZDIwLWJmMDQtYjA3YzNmMGYyODg3ZTNhNTNlMmEtNzQ1YS00M2Y4LWI2N2YtODY4MDg5OGNmYzNj

URL to long

The issue is when it comes into the method above returnurl is /connect/authorize/callback?client_id=XenaClient which is not the full url I am sending 1457 long which I suspect is too long for the server to parse?

Question

So how do I return the user to the application if the request is too long. Note defaulting it back to a single url wont work as we have several applications that use this identity server and it will not be possible to know which application the user originally came from.

1
Would the -1 person mind commenting on the issue. I am happy to edit the question and add anymore information you need. I feel i have added enough code that it should be testable.DaImTo
Would you mind accepting my edit, fixing your to/too wording?Matěj Štágl
There's no need to redirect back to the application after they confirm their email. If you really need to do it you can provide a link on the confirm email page at Identity Server.....no need to embed it in the URL.Brad
@Brad I disagree and so do my customers. We have five applications that all use this identity server for login. If a user tries to use application one and doesn't have an account on the identity server they create a new user. Confirm their email. How do i know to redirect them to application one and not application five? Users should not be stuck on the identity server they should be sent back to the application they originally tried to use. We are adding new sub applications all the time displaying a huge list of all applications would not be practical.DaImTo
But where are they being returned to? The confirm email request has come from a link in an email....not the app. Your return_url is going to the authorize endpoint at Identity Server and your redirect_uri parameter is going to the signin callback at your app. Perhaps you could show the code that generates the confirm email link.Brad

1 Answers

0
votes

I finally got this working. When the user registers i have the returnUrl, which contains the redirect_uri. For now we are going to assume that the application is on the same domain and port. So i rip out the redirect uri.

var pat = "redirect_uri=([^&]+)";
var r = new Regex(pat, RegexOptions.IgnoreCase);
var m = r.Match(returnurl);

Then I can add this smaller uri to the email confromation link

public static string EmailConfirmationLink(this IUrlHelper urlHelper, string userId, string code, string scheme, string returnUrl = "")
    {
        return urlHelper.Action(
            action: nameof(AccountController.ConfirmEmail),
            controller: "Account",
            values: new { userId, code, returnUrl },
            protocol: scheme);
    }

When the user clicks on the link I confirm their email and reroutethem back to the domain i ripped from the redirect uri

return Redirect(returnUrl);

issues

Now this should work assuming that the redirect uri and the host of the original application are on the same domain. To my knowledge they currently are. A bonus result will be that if they try to use a localhost redirect uri in production its going to cause major issues and not be able to redirect properly. This is probably a good thing as i would rather third party developers not have localhost as a redirect uri in production.

If anyone has a better solution i would still love to hear it as this feels like a slight hack. But we needed this dealt with ASAP so i have decided to live with the hack until we find a better solution