IdentityModel / oidc-client-js

OpenID Connect (OIDC) and OAuth2 protocol support for browser-based JavaScript applications
Apache License 2.0
2.43k stars 842 forks source link

Angular application Signin Redirect fails with “invalid_grant” error when running on different machine than the IDP #1325

Closed ARM-Source closed 3 years ago

ARM-Source commented 3 years ago

Here is the Stackoverflow question: https://stackoverflow.com/questions/66687890/angular-application-signin-redirect-fails-with-invalid-grant-error-when-runnin

I will paste the entire question in here aswell.

I am using oidc-client with Angular to log in to my identity server. When running both applications on the same machine everything works perfectly.

However when I run my Identity Server on a Web Apps server and my Angular Application on a Static Web App I get an error "invalid_grant".

PROBLEM DESCRIPTION

  1. User clicks on Login button and gets redirected to the login screen of Identity Server
  2. User enters Password and Username and clicks Log In
  3. Identity Server redirects to the "signin-callback" link and I get the blank signin-callback page because signin callback is only a .ts script
  4. This URL appears in the header: https://white-wave-0ca3e8803.azurestaticapps.net/signin-callback?code=l5-p3B5IGifAZ3ijIUgKmLl7aL2g45Fh5JLmluOj3NA&scope=openid%20profile&state=6503e1f5f176411a890ac50a4d0ecb84&session_state=aPnjQ5ZUiMCDKkAztm0O0K4quSkfSlWRZd--YuK73Oc.NVxBA5K6RH5_ptpDobxmxA
Under network we have a red "Token" error. Containing Response Header
HTTP/1.1 400 Bad Request
Cache-Control: no-store, no-cache, max-age=0
Pragma: no-cache
Content-Length: 25
Content-Type: application/json; charset=UTF-8
Server: Microsoft-IIS/10.0
Strict-Transport-Security: max-age=2592000
Access-Control-Allow-Origin: https://white-wave-0ca3e8803.azurestaticapps.net/dashboard X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=1fa22e5e18dd42b9d22d6c2c620b562f117da68736f4d32b741538a2d054d95c;Path=/;HttpOnly;Secure;Domain=hansecoreidp-staging.azurewebsites.net
Set-Cookie: ARRAffinitySameSite=1fa22e5e18dd42b9d22d6c2c620b562f117da68736f4d32b741538a2d054d95c;Path=/;HttpOnly;SameSite=None;Secure;Domain=hansecoreidp-staging.azurewebsites.net
Date: Thu, 18 Mar 2021 08:34:39 GMT

Error Message
{"error":"invalid_grant"}
  1. When I refresh I get the error Error: Uncaught (in promise): Error: No matching state found in storage the local storage, session storage and cookies are empty.
  2. When I delete the everything after my base URL https://white-wave-0ca3e8803.azurestaticapps.net, navigate to the base url and click login again, the login works and in the storage I all of a sudden have Cookie Storage A cookie containing AAR Affinity, etc from Identity server Session Storage I have the access_token, id_token, profile, scope, etc. Local Storage Authority, client_id, etc.

ASSUMPTION I think the Angular application is having trouble storing the information from the signin-callback in the application storage.

IDENTITY SERVER CONFIGURATION CODE

public static IEnumerable<Client> StagingClients (IConfiguration configuration) =>
        new Client[]
        {
            new Client
            {
                ClientName = "HAnsecore.Web",
                ClientId = "clientid",
                AllowedGrantTypes = GrantTypes.Code,
                AccessTokenType = AccessTokenType.Jwt,
                RedirectUris = new List<string>{ "https://white-wave-0ca3e8803.azurestaticapps.net/signin-callback" },
                RequirePkce = true,
                AllowAccessTokensViaBrowser = true,
                AllowedScopes =
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    "hansecoreCQRSApi",
                    IdentityServerConstants.StandardScopes.OfflineAccess
                },
                AllowedCorsOrigins = { "https://white-wave-0ca3e8803.azurestaticapps.net" },
                AllowOfflineAccess = true,
                RequireClientSecret = false,
                PostLogoutRedirectUris = new List<string> { "https://white-wave-0ca3e8803.azurestaticapps.net/signout-callback" },
                RequireConsent = false,
                AccessTokenLifetime = 600
            }
        };

ANGULAR OIDC-CLIENT AUTH CONFIG CODE

private get idpSettings() : UserManagerSettings {
return {
  authority: environment.idpAuthority,
  client_id: environment.clientId,
  redirect_uri: `${environment.clientRoot}/signin-callback`,
  scope: "openid profile hansecoreCQRSApi offline_access",
  response_type: "code",

  post_logout_redirect_uri: `${environment.clientRoot}/signout-callback`
}
}

SIGNIN REDIRECT CALLBACK CODE User Manager is an inherited class from oidc-client. When debugging the code does not enter the .then and I can't debug any further than here. But I think whatever happens after this is where the code fails.

public finishLogin = (): Promise<User> => {
return this._userManager.signinRedirectCallback()
.then(user => {
  this._loginChangedSubject.next(this.checkUser(user));
  return user;
})
}

SIGNIN CALLBACK CODE

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../../../core/services/auth.service';

@Component({
  selector: 'app-signin-redirect-callback',
  template: `<div></div>`
})
export class SigninRedirectCallbackComponent implements OnInit {

  constructor(private _authService: AuthService, private _router: Router) { }
  ngOnInit(): void {
    this._authService.finishLogin()
    .then(_ => {
      this._router.navigate(['/'], { replaceUrl: true });
    })
  }

}

NETWORK PICTURE Network traffic on fail image

If theres anything missing in my question at all please let me know.

EVNIRONMENT FILE

export const environment = {
  environmentName: 'STAGE',
  production: false,
  apiRoot: 'https://hansecoreapi-staging.azurewebsites.net/api/',
  clientRoot: 'https://white-wave-0ca3e8803.azurestaticapps.net',
  idpAuthority: 'https://hansecoreidp-staging.azurewebsites.net',
  clientId: '54212148-15C1-40F9-BA07-E3CE748A7C7F'
};
brockallen commented 3 years ago

If it gets to the point where it makes the token request, then everything is fine in the client from oidc-client-js's perspective. Invalid grant means the code is invalid, but you'd need to check your token server logs. Refreshing the page will trigger invalid state error, because the state that was holding the prior request's data was consumed.

ARM-Source commented 3 years ago

Hey brock! Thanks for answering. I Can't get Identity Server to Log to Azure Log Stream with the Default Identity Server 4 settings, do you have any hints on what I should be doing? My code looks identical to this http://docs.identityserver.io/en/latest/topics/logging.html, in the mean while I am going to look at the deployment documentation for Identity Server 4 see if there's a solution there. Do I need a Certificate or can I use a the self signed one builder.AddDeveloperSigningCredential();?

robntracts commented 3 years ago

I believe we are also having this issue. @ARM-Source is this issue for every user or only specific users?

ARM-Source commented 3 years ago

Hi rob! Its for every user on dev, staging and production environments. My workaround is to switch to the Implicit flow. With me it also seemed to be that the code was to long for the URL, although I cannot say for certain. https://github.com/IdentityModel/oidc-client-js/issues/1320