Search code examples
angularidentityserver4oidc-client-js

Identity Server empty cookies on production


I've an Identity Server 4 app with Angular client using oidc-client. The problem is that in production the method addUserSignedOut doesn't stop to get called after I login in the client. I test it locally and works fine.

I think the problem could be related with the cookies not present on deployment. I check on checksession getCookies() method and cookies are empty (document.cookie = "") after login, any idea how to fix that?

This is my IDP code:

  public void ConfigureServices(IServiceCollection services)
    {
        string connectionString = Configuration.GetConnectionString("DefaultConnection");
        var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;



        services.AddDataProtection()
            .AddKeyManagementOptions(dp => dp.NewKeyLifetime = TimeSpan.FromDays(90));
            //.PersistKeysToAzureBlobStorage(new Uri("<blobUriWithSasToken>"))
            //.ProtectKeysWithAzureKeyVault("<keyIdentifier>", "<clientId>", "<clientSecret>");

        services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString));

        services.AddIdentity<ApplicationUser, IdentityRole>(options => {
            options.Password.RequiredLength = 6;            // Passwords must be at least 6 characters
            options.Password.RequireLowercase = true;       // Passwords must have at least one lowercase ('a'-'z')
            options.Password.RequireUppercase = true;       // Passwords must have at least one uppercase ('A'-'Z')
            options.Password.RequireDigit = true;           // Passwords must have at least one digit ('0'-'9')
            options.Password.RequireNonAlphanumeric = true; // Passwords must have at least one non alphanumeric character
            options.Password.RequiredUniqueChars = 1;       // Passwords must use at least 1 different characters
        })
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

        services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1).AddXmlSerializerFormatters();

        services.Configure<IISOptions>(iis =>
        {
            iis.AuthenticationDisplayName = "Windows";
            iis.AutomaticAuthentication = false;
        });

        services.AddTransient<IProfileService, ProfileService>();



        var builder = services.AddIdentityServer(
            options =>
            {
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseSuccessEvents = true;
            }
        )
        // this adds the config data from DB (clients, resources)
        .AddConfigurationStore(options =>
        {
            options.ConfigureDbContext = b =>
                b.UseSqlServer(connectionString,
                    sql => sql.MigrationsAssembly(migrationsAssembly));
        })


        // this adds the operational data from DB (codes, tokens, consents)
        .AddOperationalStore(options =>
        {
            options.ConfigureDbContext = b =>
                b.UseSqlServer(connectionString,
                    sql => sql.MigrationsAssembly(migrationsAssembly));

            // this enables automatic token cleanup. this is optional.
            options.EnableTokenCleanup = true;
        });


        // Add SAML SSO services.
        services.AddSaml(Configuration.GetSection("SAML"));

        builder.Services.Configure<SecurityStampValidatorOptions>(opts =>
        {
            opts.OnRefreshingPrincipal = SecurityStampValidatorCallback.UpdatePrincipal;
        });

        services.AddAuthentication(options => {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
       .AddCookie("Cookies", opts =>
       {
           opts.SlidingExpiration = true;
           opts.ExpireTimeSpan = TimeSpan.FromMinutes(15);
       });

        if (Environment.IsDevelopment() || Environment.EnvironmentName == "local" )
        {
            builder.AddDeveloperSigningCredential();
        }
        else
        {
            X509Certificate2 cert = null;
            using (X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
            {
                certStore.Open(OpenFlags.ReadOnly);
                X509Certificate2Collection certCollection = certStore.Certificates.Find(
                    X509FindType.FindByThumbprint,
                    Configuration.GetSection("Certificate").GetValue<string>("thumbprint"),
                    false);
                // Get the first cert with the thumbprint
                if (certCollection.Count > 0)
                {
                    cert = certCollection[0];
                    Log.Logger.Information($"Successfully loaded cert from registry: {cert.Thumbprint}");
                }
            }

            // Fallback to local file for development
            if (cert == null)
            {
                throw new Exception("Cannot find any Certificate");
            }
            builder.AddSigningCredential(cert);
        }
    }

    public void Configure(IApplicationBuilder app)
    {
        if (Environment.IsDevelopment() || Environment.EnvironmentName == "local")
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();//SSO
        }

        app.UseHttpsRedirection();//SSO
        app.UseStaticFiles();
        app.UseCookiePolicy();//SSO
        app.UseIdentityServer();
        app.UseAuthentication();//SSO
        app.UseSaml();// Use SAML middleware. 
        app.UseMvcWithDefaultRoute();
    }

IDP logout controller:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Logout(LogoutInputModel model)
    {
        // build a model so the logged out page knows what to display
        var vm = await BuildLoggedOutViewModelAsync(model.LogoutId);

        if (User?.Identity.IsAuthenticated == true)
        {
            // Request logout at the service provider(SAML).
            await InitiateSingleLogout();

            // delete local authentication cookie
            await _signInManager.SignOutAsync();

            // raise the logout event
            await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
        }

        if (vm.PostLogoutRedirectUri != null) {
            return Redirect(vm.PostLogoutRedirectUri);
        }

         // since we don't have a valid context, then we just go back to the home page
        return Redirect("~/");

    }

SAML logout:

    private async Task InitiateSingleLogout()
    {
        var ssoState = await _samlIdentityProvider.GetStatusAsync();
        if (await ssoState.CanSloAsync())
        {
            // Request logout at the service provider(s).
            await _samlIdentityProvider.InitiateSloAsync();
        }
     }

Angular client oidc-client settings:

const settings: any = {
  authority: `${environment.identity_server_url}`,
  client_id: 'js',
  redirect_uri: `${environment.login_redirect}/signin-oidc`,
  response_type: 'id_token token',
  scope: 'openid profile salesforce api1',
  post_logout_redirect_uri: `${environment.login_redirect}`,
  userStore: new WebStorageStateStore({ store: window.localStorage }),
  silent_redirect_uri: `${environment.login_redirect}/signin-oidc-silent`,
  // automaticSilentRenew: true
};

Handle logout event:

 this.mgr.events.addUserSignedOut(() => {
  this.startSigninMainWindow({ external_logout: true })
 })

This is my guard where I check if the user is Logged in and call signinRedirect():

export class AuthGuardService implements CanActivate {

  constructor(
    private authService: AuthService
  ) { }
  canActivate() {
    const isLoggedIn = this.authService.isLoggedInObs();
    isLoggedIn.subscribe(loggedin => {
      if (!loggedin) {
        this.authService.startSigninMainWindow();
      }
    });
    return isLoggedIn;

  }

}

This is the AuthService class where all the logic about the oidc-client lie.

export class AuthService {
  mgr: UserManager = new UserManager(settings);
  userLoadededEvent: EventEmitter<User> = new EventEmitter<User>();
  currentUser: User;
  loggedIn = false;
  authHeaders: Headers;

  private accountID: string;
  private accountToken: string;
  private internInfoSubject = new BehaviorSubject<InternUser>(null);
  public readonly internInfo$ = this.internInfoSubject
    .asObservable()
    .pipe(
      filter(user => user !== null),
      distinctUntilChanged()
      );

  constructor(
    private router: Router,
    private internPortalService: InternPortalService,
    private apiService: ApiService,
    private http: HttpClient
  ) {

    this.mgr.events.addUserSignedOut(() => {
      this.startSigninMainWindow({ external_logout: true })
    })
  }

  getUser() {
    this.mgr
      .getUser()
      .then(user => {
        console.log('got user', user);
        this.currentUser = user;
        this.userLoadededEvent.emit(user);
      })
      .catch(function(err) {
        console.log(err);
      });
  }

  startSigninMainWindow(query = {}) {
    this.mgr.signinRedirect({extraQueryParams: query});
  }

  endSigninMainWindow() {
    this.mgr
      .signinRedirectCallback()
      .then(user => {
        console.log('signed in', user);
        this.currentUser = user;
        this.setLocalStorage();
      })
      .catch(function(err) {
        console.log(err);
      });
  }

  endSigninSilentMainWindow() {
    this.mgr
      .signinSilentCallback()
      .then(() => {
        console.log('end silent signed in');
      })
      .catch(function(err) {
        console.log(err);
      });
  }

  changePassword(): Observable<any> {
    const params = new HttpParams()
      .set('userId', this.currentUser.profile.sub)
      .set('passwordAction', '2')
      .set('redirectUrl', window.location.href);
    return this.apiService.getIdentityServer('/Token', params);
  }

  startSignoutMainWindow() {
    this.mgr
      .signoutRedirect()
      .then(function(resp) {
        console.log('signed out', resp);
        // setTimeout(5000, () => {
        //   console.log('testing to see if fired...');

        // });
      })
      .catch(function(err) {
        console.log(err);
      });
  }

  isLoggedInObs(): Observable<boolean> {
    return observableFrom(this.mgr.getUser()).pipe(
      map<User, boolean>(user => {
        if (user) {
          if (!this.internPortalService.getAccountId()) {
            this.currentUser = user;
            this.setLocalStorage();
          }
          return true;
        } else {
          return false;
        }
      })
    );
  }

  onSignOut(callback: Function){
    this.mgr.events.addUserSignedOut(resp => {
      console.log("user signed out");
      callback();
    });
    }

  get authenticationInfo(): InternUser {
    return this.internInfoSubject.value;
  }

  private setLocalStorage() {
    this.accountID = this.currentUser.profile.account_id;
    this.accountToken = this.currentUser.access_token;
    this.internPortalService.setAccountId(this.accountID, this.accountToken);
    this.internPortalService
      .getIntern()
      .subscribe(res => this.updateToken(res));
  }

  updateToken(internUser: any): void {
    console.log(internUser);
    if (!internUser) {
      return;
    }
    // TODO: Refactor once BE migration is completed
    internUser.auth = this.currentUser;
    internUser.state_locales = this.internPortalService.getStateLocales(
      internUser.state
    );
    this.internInfoSubject.next(internUser);
    this.router.navigate(['/intern-portal']);
  }

  // TODO: To be removed after QA
  public updateLocale(counter: number): void {
    const stateList = ['TX', 'MI', 'AZ', 'NC', 'SC', 'FL', 'NV', 'IN'];
    const newUser = this.authenticationInfo;
    newUser.state = stateList[counter];
    newUser.state_locales = this.internPortalService.getStateLocales(
      newUser.state
    );
    console.log(`An user from: ${newUser.state_locales.state} was loaded`);
    this.internInfoSubject.next(newUser);
  }

  logout(): void {
    localStorage.clear();
    this.internInfoSubject.next(null);
  }
}

And the signin-oidc-silent component:

export class SigninOidcComponent implements OnInit {
  private element: any;

  constructor(private authService: AuthService) {
  }

  ngOnInit() {
    console.log('init oidc logic');
    this.authService.endSigninMainWindow();
  }

}

I just don't know why the infinite loop happens on the hosted apps. Actually if I use the client locally and point to my hosted IDP I get the same infinite loop.

I don't see any error on console, only this warning ResponseValidator._processSigninParams: Response was error login_required

Here some IDP logs:

2019-04-15 11:16:49.383 +00:00 [DBG] Request path /connect/authorize matched to endpoint type Authorize
2019-04-15 11:16:49.418 +00:00 [DBG] Endpoint enabled: Authorize, successfully created handler: IdentityServer4.Endpoints.AuthorizeEndpoint
2019-04-15 11:16:49.419 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeEndpoint for /connect/authorize
2019-04-15 11:16:49.423 +00:00 [DBG] Start authorize request
2019-04-15 11:16:49.435 +00:00 [DBG] User in authorize request: cfd7214d-305d-4d91-9d50-671dac6b37d8
2019-04-15 11:16:49.436 +00:00 [DBG] Start authorize request protocol validation
2019-04-15 11:16:49.566 +00:00 [DBG] js found in database: true
2019-04-15 11:16:49.569 +00:00 [DBG] client configuration validation for client js succeeded.
2019-04-15 11:16:49.624 +00:00 [DBG] Found ["openid","profile","salesforce"] identity scopes in database
2019-04-15 11:16:49.673 +00:00 [DBG] Found ["api1"] API scopes in database
2019-04-15 11:16:49.687 +00:00 [DBG] Found ["openid","profile","salesforce"] identity scopes in database
2019-04-15 11:16:49.703 +00:00 [DBG] Found ["api1"] API scopes in database
2019-04-15 11:16:49.712 +00:00 [DBG] Calling into custom validator: IdentityServer4.Validation.DefaultCustomAuthorizeRequestValidator
2019-04-15 11:16:49.755 +00:00 [INF] ValidatedAuthorizeRequest
{"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc","AllowedRedirectUris":["http://localhost:5003/callback.html","http://localhost:5003/signin-oidc","http://localhost:4200/signin-oidc","http://localhost:4200/signin-oidc-silent","https://tt-prince-internportal.azurewebsites.net/signin-oidc","https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc-silent"],"SubjectId":"cfd7214d-305d-4d91-9d50-671dac6b37d8","ResponseType":"id_token token","ResponseMode":"fragment","GrantType":"implicit","RequestedScopes":"openid profile salesforce api1","State":"42a8d9eda2a94c61a4f8ac2f13bbee52","UiLocales":null,"Nonce":"76c3d45a35524c908b1593454305a796","AuthenticationContextReferenceClasses":null,"DisplayMode":null,"PromptMode":null,"MaxAge":null,"LoginHint":null,"SessionId":"a593b46f1553fa4d5beae979ec6475ba","Raw":{"client_id":"js","redirect_uri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc","response_type":"id_token token","scope":"openid profile salesforce api1","state":"42a8d9eda2a94c61a4f8ac2f13bbee52","nonce":"76c3d45a35524c908b1593454305a796","external_logout":"true"},"$type":"AuthorizeRequestValidationLog"}
2019-04-15 11:16:49.758 +00:00 [DBG] Client is configured to not require consent, no consent is required
2019-04-15 11:16:49.759 +00:00 [DBG] Creating Implicit Flow response.
2019-04-15 11:16:49.760 +00:00 [DBG] Getting claims for access token for client: js
2019-04-15 11:16:49.765 +00:00 [DBG] Getting claims for access token for subject: cfd7214d-305d-4d91-9d50-671dac6b37d8
2019-04-15 11:16:49.769 +00:00 [DBG] Claim types from profile service that were filtered: ["sub","idp","amr","auth_time"]
2019-04-15 11:16:49.812 +00:00 [DBG] Getting claims for identity token for subject: cfd7214d-305d-4d91-9d50-671dac6b37d8 and client: js
2019-04-15 11:16:49.814 +00:00 [DBG] In addition to an id_token, an access_token was requested. No claims other than sub are included in the id_token. To obtain more user claims, either use the user info endpoint or set AlwaysIncludeUserClaimsInIdToken on the client configuration.
2019-04-15 11:16:49.835 +00:00 [INF] {"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc","Endpoint":"Authorize","SubjectId":"cfd7214d-305d-4d91-9d50-671dac6b37d8","Scopes":"openid profile salesforce api1","GrantType":"implicit","Tokens":[{"TokenType":"id_token","TokenValue":"****UIMg","$type":"Token"},{"TokenType":"access_token","TokenValue":"****NWSw","$type":"Token"}],"Category":"Token","Name":"Token Issued Success","EventType":"Success","Id":2000,"Message":null,"ActivityId":"0HLLVFNQC24O5:00000001","TimeStamp":"2019-04-15T11:16:49.0000000Z","ProcessId":11056,"LocalIpAddress":"127.0.0.1:28158","RemoteIpAddress":"167.57.108.74","$type":"TokenIssuedSuccessEvent"}
2019-04-15 11:16:49.845 +00:00 [INF] Authorize endpoint response
{"SubjectId":"cfd7214d-305d-4d91-9d50-671dac6b37d8","ClientId":"js","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc","State":"42a8d9eda2a94c61a4f8ac2f13bbee52","Scope":"openid profile salesforce api1","Error":null,"ErrorDescription":null,"$type":"AuthorizeResponseLog"}
2019-04-15 11:16:56.059 +00:00 [DBG] CORS request made for path: /.well-known/openid-configuration from origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.067 +00:00 [DBG] Origin https://tt-prince-internportal.azurewebsites.net is allowed: true
2019-04-15 11:16:56.069 +00:00 [DBG] CorsPolicyService allowed origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.071 +00:00 [DBG] Request path /.well-known/openid-configuration matched to endpoint type Discovery
2019-04-15 11:16:56.076 +00:00 [DBG] Endpoint enabled: Discovery, successfully created handler: IdentityServer4.Endpoints.DiscoveryEndpoint
2019-04-15 11:16:56.077 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.DiscoveryEndpoint for /.well-known/openid-configuration
2019-04-15 11:16:56.079 +00:00 [DBG] Start discovery request
2019-04-15 11:16:56.118 +00:00 [DBG] Found ["openid","profile","salesforce","role","api1"] as all scopes in database
2019-04-15 11:16:56.341 +00:00 [DBG] CORS request made for path: /.well-known/openid-configuration from origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.347 +00:00 [DBG] Origin https://tt-prince-internportal.azurewebsites.net is allowed: true
2019-04-15 11:16:56.349 +00:00 [DBG] CorsPolicyService allowed origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.350 +00:00 [DBG] Request path /.well-known/openid-configuration matched to endpoint type Discovery
2019-04-15 11:16:56.351 +00:00 [DBG] Endpoint enabled: Discovery, successfully created handler: IdentityServer4.Endpoints.DiscoveryEndpoint
2019-04-15 11:16:56.352 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.DiscoveryEndpoint for /.well-known/openid-configuration
2019-04-15 11:16:56.353 +00:00 [DBG] Start discovery request
2019-04-15 11:16:56.374 +00:00 [DBG] Found ["openid","profile","salesforce","role","api1"] as all scopes in database
2019-04-15 11:16:56.381 +00:00 [DBG] Request path /connect/checksession matched to endpoint type Checksession
2019-04-15 11:16:56.389 +00:00 [DBG] Endpoint enabled: Checksession, successfully created handler: IdentityServer4.Endpoints.CheckSessionEndpoint
2019-04-15 11:16:56.390 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.CheckSessionEndpoint for /connect/checksession
2019-04-15 11:16:56.392 +00:00 [DBG] Rendering check session result
2019-04-15 11:16:56.613 +00:00 [DBG] CORS request made for path: /.well-known/openid-configuration/jwks from origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.618 +00:00 [DBG] Origin https://tt-prince-internportal.azurewebsites.net is allowed: true
2019-04-15 11:16:56.621 +00:00 [DBG] CorsPolicyService allowed origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.622 +00:00 [DBG] Request path /.well-known/openid-configuration/jwks matched to endpoint type Discovery
2019-04-15 11:16:56.624 +00:00 [DBG] Endpoint enabled: Discovery, successfully created handler: IdentityServer4.Endpoints.DiscoveryKeyEndpoint
2019-04-15 11:16:56.625 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.DiscoveryKeyEndpoint for /.well-known/openid-configuration/jwks
2019-04-15 11:16:56.628 +00:00 [DBG] Start key discovery request
2019-04-15 11:16:56.719 +00:00 [DBG] Request path /connect/authorize matched to endpoint type Authorize
2019-04-15 11:16:56.722 +00:00 [DBG] Endpoint enabled: Authorize, successfully created handler: IdentityServer4.Endpoints.AuthorizeEndpoint
2019-04-15 11:16:56.723 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeEndpoint for /connect/authorize
2019-04-15 11:16:56.725 +00:00 [DBG] Start authorize request
2019-04-15 11:16:56.726 +00:00 [DBG] No user present in authorize request
2019-04-15 11:16:56.727 +00:00 [DBG] Start authorize request protocol validation
2019-04-15 11:16:56.743 +00:00 [DBG] js found in database: true
2019-04-15 11:16:56.748 +00:00 [DBG] client configuration validation for client js succeeded.
2019-04-15 11:16:56.757 +00:00 [DBG] Found ["openid"] identity scopes in database
2019-04-15 11:16:56.760 +00:00 [DBG] Found [] API scopes in database
2019-04-15 11:16:56.767 +00:00 [DBG] Found ["openid"] identity scopes in database
2019-04-15 11:16:56.772 +00:00 [DBG] Found [] API scopes in database
2019-04-15 11:16:56.773 +00:00 [DBG] Calling into custom validator: IdentityServer4.Validation.DefaultCustomAuthorizeRequestValidator
2019-04-15 11:16:56.775 +00:00 [INF] ValidatedAuthorizeRequest
{"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","AllowedRedirectUris":["http://localhost:5003/callback.html","http://localhost:5003/signin-oidc","http://localhost:4200/signin-oidc","http://localhost:4200/signin-oidc-silent","https://tt-prince-internportal.azurewebsites.net/signin-oidc","https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc-silent"],"SubjectId":"anonymous","ResponseType":"id_token","ResponseMode":"fragment","GrantType":"implicit","RequestedScopes":"openid","State":"170ef6a2eda34bc6a7c0a5d79fc25a7a","UiLocales":null,"Nonce":"1f0b1599850a4c6882f9e69ceda252ee","AuthenticationContextReferenceClasses":null,"DisplayMode":null,"PromptMode":"none","MaxAge":null,"LoginHint":null,"SessionId":null,"Raw":{"client_id":"js","redirect_uri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","response_type":"id_token","scope":"openid","state":"170ef6a2eda34bc6a7c0a5d79fc25a7a","nonce":"1f0b1599850a4c6882f9e69ceda252ee","prompt":"none"},"$type":"AuthorizeRequestValidationLog"}
2019-04-15 11:16:56.776 +00:00 [INF] Showing error: prompt=none was requested but user is not authenticated
2019-04-15 11:16:56.778 +00:00 [INF] {"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","AllowedRedirectUris":["http://localhost:5003/callback.html","http://localhost:5003/signin-oidc","http://localhost:4200/signin-oidc","http://localhost:4200/signin-oidc-silent","https://tt-prince-internportal.azurewebsites.net/signin-oidc","https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc-silent"],"SubjectId":"anonymous","ResponseType":"id_token","ResponseMode":"fragment","GrantType":"implicit","RequestedScopes":"openid","State":"170ef6a2eda34bc6a7c0a5d79fc25a7a","UiLocales":null,"Nonce":"1f0b1599850a4c6882f9e69ceda252ee","AuthenticationContextReferenceClasses":null,"DisplayMode":null,"PromptMode":"none","MaxAge":null,"LoginHint":null,"SessionId":null,"Raw":{"client_id":"js","redirect_uri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","response_type":"id_token","scope":"openid","state":"170ef6a2eda34bc6a7c0a5d79fc25a7a","nonce":"1f0b1599850a4c6882f9e69ceda252ee","prompt":"none"},"$type":"AuthorizeRequestValidationLog"}
2019-04-15 11:16:56.779 +00:00 [INF] {"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","Endpoint":"Authorize","SubjectId":null,"Scopes":"openid","GrantType":"implicit","Error":"login_required","ErrorDescription":null,"Category":"Token","Name":"Token Issued Failure","EventType":"Failure","Id":2001,"Message":null,"ActivityId":"0HLLVFNQC24O6:00000002","TimeStamp":"2019-04-15T11:16:56.0000000Z","ProcessId":11056,"LocalIpAddress":"127.0.0.1:28158","RemoteIpAddress":"167.57.108.74","$type":"TokenIssuedFailureEvent"}
2019-04-15 11:16:57.174 +00:00 [DBG] CORS request made for path: /connect/userinfo from origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:57.178 +00:00 [DBG] Origin https://tt-prince-internportal.azurewebsites.net is allowed: true
2019-04-15 11:16:57.179 +00:00 [DBG] CorsPolicyService allowed origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:57.180 +00:00 [DBG] Request path /connect/userinfo matched to endpoint type Userinfo
2019-04-15 11:16:57.185 +00:00 [DBG] Endpoint enabled: Userinfo, successfully created handler: IdentityServer4.Endpoints.UserInfoEndpoint
2019-04-15 11:16:57.186 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.UserInfoEndpoint for /connect/userinfo
2019-04-15 11:16:57.188 +00:00 [DBG] Start userinfo request
2019-04-15 11:16:57.189 +00:00 [DBG] Bearer token found in header
2019-04-15 11:16:57.240 +00:00 [DBG] js found in database: true
2019-04-15 11:16:57.241 +00:00 [DBG] client configuration validation for client js succeeded.
2019-04-15 11:16:57.269 +00:00 [DBG] js found in database: true
2019-04-15 11:16:57.270 +00:00 [DBG] client configuration validation for client js succeeded.
2019-04-15 11:16:57.281 +00:00 [DBG] Calling into custom token validator: IdentityServer4.Validation.DefaultCustomTokenValidator
2019-04-15 11:16:57.283 +00:00 [DBG] Token validation success

Solution

  • I finally find where to set the SameSite.None for the cookie in order to allow the browser send it back to IS when checking for session state. In my case I'm using ASP.NET Core Identity so the code is:

    builder.Services.ConfigureApplicationCookie(options =>
    {    
        options.Cookie.IsEssential = true;           
        // we need to disable to allow iframe for authorize requests
        options.Cookie.SameSite = AspNetCore.Http.SameSiteMode.None;
    });
    

    after:

    var builder = services.AddIdentityServer(options =>
    ...