12
votes

We have a React SPA which was initially created using the SPA templates and running on .NET Core 3 preview 7. The React SPA "The client" was configured for implicit flow and successfully using the oidc-client. All working.

Here is the client config in my startup.cs:

        var mySPAClient = new IdentityServer4.Models.Client()
        {
            AccessTokenLifetime = accessTokenLifetime,
            RedirectUris =
                {
                    $"{host}/authentication/login-callback",
                    $"{host}/silent-refresh.html"
                },
            PostLogoutRedirectUris =
                {
                    $"{host}/authentication/logout-callback"
                },
            ClientId = "projectName.web",
            AllowedScopes =
                {
                    "projectName.webAPI",
                    "openid",
                    "profile"
                },
            ClientName = "projectName.web",
            RequireConsent = false,
            AllowedGrantTypes =
                {
                    IdentityModel.OidcConstants.GrantTypes.Implicit
                },
            AllowAccessTokensViaBrowser = true,
        };

But now when i upgrade to preview 8 for any assembly that was preview 7 I am getting the following error in the logs

[10:55:34 Error] Invalid grant type for client: "authorization_code" AuthorizeRequestValidationLog { ClientId: "projectName.web", ClientName: "projectName.web", RedirectUri: "https://localhost:44343/authentication/login-callback", AllowedRedirectUris: ["https://localhost:44343/authentication/login-callback", "https://localhost:44343/silent-refresh.html"], SubjectId: "anonymous", ResponseType: "code", ResponseMode: "query", GrantType: "authorization_code", RequestedScopes: "", State: "a1e84334a8c94b7db599ddb9336447c8", UiLocales: null, Nonce: null, AuthenticationContextReferenceClasses: null, DisplayMode: null, PromptMode: null, MaxAge: null, LoginHint: null, SessionId: null, Raw: [("client_id": "projectName.web"), ("redirect_uri": "https://localhost:44343/authentication/login-callback"), ("response_type": "code"), ("scope": "projectName.webAPI openid profile"), ("state": "a1e84334a8c94b7db599ddb9336447c8"), ("code_challenge": "E8p1sg1Y0TdbhxccGB-_fbx7D6GnJXfCpcYu1IHZC_k"), ("code_challenge_method": "S256"), ("prompt": "none")] } (IdentityServer4.Validation.AuthorizeRequestValidator) [10:55:34 Error] Request validation failed (IdentityServer4.Endpoints.AuthorizeEndpoint)

I don't know why it now is referring to authorization_code and this error is appearing?

Cheers for any assistance

2
Can we see your Token endpoint call? - bobek
I have the same problem. Looks like the token endpoint is called twice, and it failed the second time since the authorization code is supposed to be used only once. (There is a successful token endpoint call before this one, with a userinfo call in between). I am not sure what is causing the behavior. So far, I can tell that the login component is mounted twice, hence two LoginCallback actions in componentDidMount. Any ideas? - laorient
Hey interesting I’m away but will check it out when I get back in a week - Andrew Duffy

2 Answers

1
votes

Changing the response_type to be "token" rather than "code" and you should be ok

Update:

Make sure you provide correct authority, client_id, response_type, scope settings

0
votes

I have figured out mine. But not sure if it is applicable to yours. The problem in my case is that I have a process flow that is somehow mismatched. When I tried to modify the React with Auth sample to use EF Core, the updateState call is not made in the AuthorizeService.js/completeSignIn(). The code seems to cause another call to token endpoint before it goes back to SignIn(), with no updateState() call to save the state. And it is failing the second one since the code expired after the first call. I somehow found another source code from the React with Redux sample, which has the requisite updateState() call in the completeSignIn(). And other than the very different AuthorizeService.js file, the other authentication/authorization related code are the same between the React with Auth sample and the React with Redux sample. This is the new completeSignIn code:

    async completeSignIn(url) {
        await this.ensureUserManagerInitialized();
        try {
            const { state } = await this.userManager.readSigninResponseState(url, this.userManager.settings.stateStore);
            if (state.request_type === 'si:r' || !state.request_type) {
                let user = await this.userManager.signinRedirectCallback(url);
                this.updateState(user);
                return this.success(state.data.userState);
            }
            if (state.request_type === 'si:p') {
                await this.userManager.signinSilentCallback(url);
                return this.success(undefined);
            }
            if (state.request_type === 'si:s') {
              await this.userManager.signinSilentCallback(url);
              return this.success(undefined);
            }

            throw new Error(`Invalid login mode '${state.request_type}'.`);
        } catch (signInResponseError) {
            console.log('There was an error signing in', signInResponseError);
            return this.error('Sing in callback authentication error.');
        }
    }