lkriz
lkriz

Reputation: 21

IdentityServer4 authorization error not matching redirect URI

I have a Blazor WebAssembly application that is hosted in ASP.NET CORE server. I am using IIS in process self-contained deployment and the application is configured as a sub-application of the Default Web Site. So the URL is something like [https:]//myserver/APPLICATIONNAME/

I am getting an error saying that the redirect URI does not match the allowed URIs for the client, but in the log the two URIs are exactly the same. The redirect URI is defined in appsettings.json file.

I have followed the Microsoft docs here

This is the log error without explicit redirect URI:

{
  "ClientId": "TestBlazorAuth.Client",
  "ClientName": "TestBlazorAuth.Client",
  "AllowedRedirectUris": [
    "/authentication/login-callback"
  ],
  "SubjectId": "anonymous",
  "RequestedScopes": "",
  "Raw": {
    "client_id": "TestBlazorAuth.Client",
    "redirect_uri": "https://localhost/TestBlazorAuth/authentication/login-callback",
    "response_type": "code",
    "scope": "TestBlazorAuth.ServerAPI openid profile",
    "state": "d53f88ebd6dc413fb929f01b06cd8efa",
    "code_challenge": "XPaEMOg02714PWrx9POC3oSwsO2mXAhBe_IerH4p75E",
    "code_challenge_method": "S256",
    "prompt": "none",
    "response_mode": "query"
  }
}

This is the explicit setting:

"IdentityServer": {
    "Clients": {
      "TestBlazorAuth.Client": {
        "Profile": "IdentityServerSPA",
        "RedirectUri": "https://localhost/TestBlazorAuth/authentication/login-callback"
      }
    },
    "Key": {
      "Type": "File",
      "FilePath": "C:\\temp\\som_cert_file.pfx",
      "Password": "blablabla"
    }
  },

This is the error log when explicit setting is used:

Invalid redirect_uri: https://localhost/TestBlazorAuth/authentication/login-callback
{
  "ClientId": "TestBlazorAuth.Client",
  "ClientName": "TestBlazorAuth.Client",
  "AllowedRedirectUris": [
    "https://localhost/TestBlazorAuth/authentication/login-callback"
  ],
  "SubjectId": "anonymous",
  "RequestedScopes": "",
  "Raw": {
    "client_id": "TestBlazorAuth.Client",
    "redirect_uri": "https://localhost/TestBlazorAuth/authentication/login-callback",
    "response_type": "code",
    "scope": "TestBlazorAuth.ServerAPI openid profile",
    "state": "3b121b72d20640cb8c7b74f783b5d914",
    "code_challenge": "WNev6kwUV7UjAhNTvvDH10vJwkEXPDev8jwNZYnsNDY",
    "code_challenge_method": "S256",
    "prompt": "none",
    "response_mode": "query"
  }
}

redirect_uri and AllowedRedirectUris[0] look exactly the same to me.

This is a trace using NLOG:

2020-06-24 14:56:05.3948||TRACE|IdentityServer4.Stores.ValidatingClientStore|Calling into client configuration validator: IdentityServer4.Validation.DefaultClientConfigurationValidator 
2020-06-24 14:56:05.4080||DEBUG|IdentityServer4.Stores.ValidatingClientStore|client configuration validation for client Integra.PCSP.Print.WebUI.Client succeeded. 
2020-06-24 14:56:05.4080||ERROR|IdentityServer4.Validation.AuthorizeRequestValidator|Invalid redirect_uri: "https://localhost/TestBlazorAuth/authentication/login-callback"

I looked at IdentityServer4 source code to check how is the comparison done, and it all seems perfectly fine:

    public class StrictRedirectUriValidator : IRedirectUriValidator
    {
        /// <summary>
        /// Checks if a given URI string is in a collection of strings (using ordinal ignore case comparison)
        /// </summary>
        /// <param name="uris">The uris.</param>
        /// <param name="requestedUri">The requested URI.</param>
        /// <returns></returns>
        protected bool StringCollectionContainsString(IEnumerable<string> uris, string requestedUri)
        {
            if (uris.IsNullOrEmpty()) return false;

            return uris.Contains(requestedUri, StringComparer.OrdinalIgnoreCase);
        }

    ...
    }

At this point I am ready to scratch the project and implement the app in MVC, it's only couple pages, so I thought it would be a great Blazor proof-of-concept. It turned out the development part is easy, the deployment is a nightmare.

Thanks for any ideas.

Upvotes: 1

Views: 1301

Answers (1)

lkriz
lkriz

Reputation: 21

The issue turned out to be with case-sensitivity. I still don't understand why though.

Here's what I did.

  1. Update Blazor wasm solution wwwroot/index.html (URI all lower-case!)
<base href="/testblazorauth/" />   
  1. Update the server project Startup.cs ( URI all lower-case!)
app.UsePathBase("/testblazorauth/");
  1. Update appsettings.json (removed the explicit RedirectUri property). The framework will use the value from the second step and correctly build the callback URI.
"IdentityServer": {
    "Clients": {
      "TestBlazorAuth.Client": {
        "Profile": "IdentityServerSPA"        
      }
    },
    "Key": {
      "Type": "File",
      "FilePath": "C:\\temp\\SOME_CERT.pfx",
      "Password": "SOME_PASSWORD"
    }
  },

In IIS, i have created new sub-application of Default Web Site with a host name "testblazorauth" (all lower-case).

Published the app with VS and ran in Chrome and got expected results and no more errors.

Upvotes: 1

Related Questions