0

Trying to build an interactive login form in a NET 6 WinForms app, using Identity Server 6 but heavily inspired on the Winforms client example provided here: https://github.com/IdentityModel/IdentityModel.OidcClient.Samples/tree/main/WinFormsWebView2/WinFormsWebView2

Getting this error rendered in the client-side 'browser':

Sorry, there was an error : invalid_request Invalid redirect_uri

On the local console of the IS6 project, it shows this error:

[23:04:00 Error] Duende.IdentityServer.Validation.AuthorizeRequestValidator Invalid redirect_uri: http://localhost/winforms.client

{
    "ClientId": "vr2-win-client",
    "ClientName": null,
    "RedirectUri": null,
    "AllowedRedirectUris": [],
    "SubjectId": "anonymous",
    "ResponseType": null,
    "ResponseMode": null,
    "GrantType": null,
    "RequestedScopes": "",
    "State": null,
    "UiLocales": null,
    "Nonce": null,
    "AuthenticationContextReferenceClasses": null,
    "DisplayMode": null,
    "PromptMode": "",
    "MaxAge": null,
    "LoginHint": null,
    "SessionId": null,
    "Raw": {
       "response_type"        : "code",
       "state"                : "IdqJr9LGl9n_0lcl0LlTVA",
       "code_challenge"       : "v7Bjclv_Ivn7Kltp-7iCOCqdUZxJIxVSf27Ecau2G2o",
       "code_challenge_method": "S256",
       "client_id"            : "vr2-win-client",
       "scope"                : "vr2-client-api offline_access openid",
       "redirect_uri"         : "http://localhost/winforms.client"
    }
},
"$type": "AuthorizeRequestValidationLog"
}

[23:04:00 Error] Duende.IdentityServer.Endpoints.AuthorizeEndpoint Request validation failed

I can't figure out why, since the specified Redirect URIs do exactly match. [Incidentally, for a quick moan: this identity server business is bafflingly difficult to get right and hard to work with. I've been at at this for weeks now, and all i want to do to is to protect one api on the backend and provision an interactive login at the frontend; there Must be an Easier Way]

This is the code in my IS client config:

public static IEnumerable<Client> Clients =>
        new List<Client>
        {
            new Client
            {
                ClientId = "vr2-win-client",
             
                AllowedScopes = new List<string>
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile
                },

                RequireClientSecret = false,
                AllowedGrantTypes = GrantTypes.Code,
                RequirePkce = true,
                RedirectUris = { "https://notused", "http://localhost/winforms.client" },
                PostLogoutRedirectUris = { "https://notused" },
                AllowOfflineAccess = true,
                RequireConsent = false

                // scopes that client has access to
                //AllowedScopes = { "vr2-client-api" }
            }
        };

And on the client side code I have this:

private async void LoginBtn_Click(object sender, EventArgs e)
        {
            var oidcOptions = new OidcClientOptions
            {
                Authority = config["IdentityServerAddress"].ToString(),
                ClientId = "vr2-win-client",
                Scope = "vr2-client-api offline_access openid",
                RedirectUri = "http://localhost/winforms.client",
                Browser = this.loginWebForm
            };
            
            OidcClient _oidcClient = new OidcClient(oidcOptions);
                        
            LoginResult loginResult = await _oidcClient.LoginAsync();

            if (loginResult.IsError)
            {
                MessageBox.Show(loginResult.Error, "Login", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            this.accessTokenLifetimeManager = new AccessTokenLifetimeManager
                (loginResult, 600, cancellationOnExitTokenSource.Token, config);

            var refreshTokenTask = Task.Run(accessTokenLifetimeManager.PeriodicallyRefreshAccessTokensWorkerTaskAsync);

            vr2Button.Enabled = true;
        } 

I am using IdentityModel.OidcClient v5.2.1 on the client side And Identity Server v6.3.2

I am super grateful for any ideas as to what I've missed or what it is that I am doing wrong here. Presumably there must be an additional validation requirement (for the redirect URL) which the error messages does not describe, any pointers would be much appreciated.

thanks

Dai
  • 141,631
  • 28
  • 261
  • 374
  • Look **closely** at the exception message and you'll see it actually says `"RedirectUri": null, "AllowedRedirectUris": []"` - which means _no `redirect_uri`_ has been stored with that IS `Client` object. – Dai Jul 12 '23 at 22:33
  • I suspect that using the C# object-initializer syntax to set `RedirectUris = { "https://notused", "http://localhost/winforms.client" }` simply causes the values to be dropped. What does your debugger say about the `IEnumerable Clients` property at runtime? – Dai Jul 12 '23 at 22:34
  • Thanks for your help. Your advice has, I think, set me potentially on the right track - I think the code configuration is being overridden at runtime by the database configuration. I'm trying now to try to work out how to migrate my code config into my database (using code) and will be posting a new question on just that. – user3561406 Jul 15 '23 at 14:15
  • https://stackoverflow.com/questions/76694217/how-to-migrate-identity-server-6-code-configuration-into-database – user3561406 Jul 15 '23 at 14:28

0 Answers0