Silent refresh not working with OIDC-client in Angular 5

不问归期 提交于 2020-01-24 03:00:42

问题


I have an issue with the silen refresh with oidc-client. The signin works fine and I'm able to acquire a token. However, the silent refresh doesn't fire, nothing happen, and when I subscribe to methods that check token expiracy (methods in subscribeevents in authservice.ts), these methods never fire, and method isLoggedIn() always return true event if the token has expired!!!!!

Someone could help me?

Here is my code :

    import { Component, OnInit } from '@angular/core';
import { UserManager } from 'oidc-client';
import { getClientSettings } from '../openIdConnectConfig';
import { AuthService } from '../services/auth.service';

@Component({
  selector: 'app-silentrefresh',
  templateUrl: './silentrefresh.component.html',
  styleUrls: ['./silentrefresh.component.css']
})
export class SilentRefreshComponent implements OnInit {


  constructor(private _authService:AuthService) {

  }

  ngOnInit() {
    this._authService.refreshCallBack();
  }


}

Then my authservice :

import { UserManagerSettings, UserManager, User } from 'oidc-client';
import { Injectable } from '@angular/core';
import { getClientSettings } from '../openIdConnectConfig';

@Injectable()
export class AuthService {

  private _manager = new UserManager(getClientSettings());
  private _user: User = null;

  constructor() {
    this._manager.getUser().then(user => {
      this._user = user;
    });

    this._manager.events.addUserLoaded(user => {
      this._user = user;
    });

    this.subscribeevents();

  }

  public isLoggedIn(): boolean {
    return this._user != null && !this._user.expired;
  }

  public getClaims(): any {
    return this._user.profile;
  }

  public subscribeevents() :void {
    this._manager.events.addSilentRenewError(() => {
      console.log("error SilentRenew");
    });

    this._manager.events.addAccessTokenExpiring(() => {
      console.log("access token expiring");
    });

    this._manager.events.addAccessTokenExpired(() => {
      console.log("access token expired");
    });
  }

  public refreshCallBack(): void
  {
    console.log("start refresh callback");
    this._manager.signinSilentCallback()
      .then(data => {console.log("suucess callback")})
      .catch(err => {
          console.log("err callback");
      });
      console.log("end refresh callback");
  }

  getUser(): any {
    return this._user;
  }

  getName(): any {
    return this._user.profile.name;
  }

  getAuthorizationHeaderValue(): string {
    return `${this._user.token_type} ${this._user.access_token}`;
  }

  startAuthentication(): Promise<void> {
    return this._manager.signinRedirect();
  }

  completeAuthentication(): Promise<void> {
    return this._manager.signinRedirectCallback().then(user => {
        this._user = user;
    });


  }
}

And my config:

import { UserManagerSettings } from "oidc-client";

export function getClientSettings(): UserManagerSettings {
  return {
      authority: 'https://login.microsoftonline.com/136544d9-038e-4646-afff-10accb370679',
      client_id: '257b6c36-1168-4aac-be93-6f2cd81cec43',
      redirect_uri: 'http://localhost:4200/auth-callback',
      //redirect_uri: 'https://demoazureadconnectangular5.azurewebsites.net/auth-callback',
      post_logout_redirect_uri: 'http://localhost:4200/',
      //post_logout_redirect_uri: 'https://demoazureadconnectangular5.azurewebsites.net/',
      response_type:"id_token",
      scope:"openid profile",
      filterProtocolClaims: true,
      loadUserInfo: true,
      automaticSilentRenew: true,
      silent_redirect_uri: 'http://localhost:4200/assets/silentrefresh',
      metadata: {
        issuer: "https://sts.windows.net/136544d9-038e-4646-afff-10accb370679/",
        authorization_endpoint: "https://login.microsoftonline.com/136544d9-038e-4646-afff-10accb370679/oauth2/authorize",
        token_endpoint: "https://login.microsoftonline.com/136544d9-038e-4646-afff-10accb370679/oauth2/token",
        //jwks_uri: "https://login.microsoftonline.com/common/discovery/keys",
        jwks_uri: "http://localhost:4200/assets/keys.json",
        //jwks_uri: "https://demoazureadconnectangular5.azurewebsites.net/assets/keys.json",
        //jwks_uri: "http://localhost:50586/api/keys",
        signingKeys: [{"ApiAccessKey": "NgixniZ0S1JHxo7GPEZYa38OBTxSA98AqJKDX5XqsJ8="}]
    }
  };
}

I also tried to use a static page like this:

<head>
    <title></title>
</head>
<body>
<script src="oidc-client.min.js"></script>
<script>
    var usermanager = UserManager().signinSilentCallback()
        .catch((err) => {
            console.log(err);
        });
</script>
</body>

It's never fired neither

In order to test quickly I setup ID token expiracy to 10 min. I use Azure AD Connect (Open Id Connect in Azure) and Microsoft says it's nit fully compatible with Open ID Connect standard.... So I don't know if it's on my side or Azure side.

Somebody can help me to solve this?


回答1:


The problem is that you are not asking access_token from azure AD, only id_token. You must set response_type to id_token token to get both tokens. This change will need also few more parameters. For example resource for your backend. I have answered similar question here. I'm using also Angular 5 and oidc client. https://stackoverflow.com/a/50922730/8081009 And I answer you here also before https://github.com/IdentityModel/oidc-client-js/issues/504#issuecomment-400056662 Here is what you need to set to get silent renew working.

includeIdTokenInSilentRenew: true
extraQueryParams: {
      resource: '10282f28-36ed-4257-a853-1bf404996b18'
}
response_type: 'id_token token',
scope: 'openid'
loadUserInfo: false,
automaticSilentRenew: true,
silent_redirect_uri: `${window.location.origin}/silent-refresh.html`,
metadataUrl: 'https://login.microsoftonline.com/YOUR_TENANT_NAME.onmicrosoft.com/.well-known/openid-configuration',
signingKeys: [
    add here keys from link below
]

https://login.microsoftonline.com/common/discovery/keys

I'm also using different static page for callback endpoint with silent renew because this way user won't notice a thing. This page is minimum possible so oidc won't load whole angular application to hidden iframe what it is using for silent renew. So this is recommended to be more efficient.

<head>
  <title></title>
</head>

<body>
  <script src="assets/oidc-client.min.js"></script>
  <script>
    new Oidc.UserManager().signinSilentCallback()
      .catch((err) => {
        console.log(err);
      });
  </script>
</body>



回答2:


I have used some different approach to initate the silentRenw, instead of using

 automaticSilentRenew: true,

I decided to explicitly call the signInSilent();. Reason for doing the i was facing some issues as automaticSilentRenew: true, was not working as expected.

I initialized the event and method in my UserAuth class constructor that implements my interface

  constructor(private oidcSettings: CoreApi.Interfaces.Authentication.OpenIDConnectionSettings)
    {
     this.userManager.events.addAccessTokenExpiring(() =>
             {
                this.userManager.signinSilent({scope: oidcSettings.scope, response_type: oidcSettings.response_type})
                        .then((user: Oidc.User) =>
                        {
                            this.handleUser(user);
                        })
                        .catch((error: Error) =>
                        {
                           //Work around to handle to Iframe window timeout errors on browsers
                            this.userManager.getUser()
                                .then((user: Oidc.User) =>
                                {
                                    this.handleUser(user);
                                });
                        });
                });
    }

Where as handleUser is just check for logged in user.

So if you initialize the signInSilent process in your constructor and then call signInSilent complete i.e. callback it may work.




回答3:


I’m using Azure Ad that is not fully compatible at 100% with open ID Connect, I just receive an ID_token and no access_token required by OIDC-CLIENT. I have to switch to Microsoft library ADAL.JS




回答4:


Not sure what oidc-client.js version you are using, this should never have worked.

```
new Oidc.UserManager().signinSilentCallback()
                  .catch((err) => {
                      console.log(err);
                  });
``

Usermanager is in **Oidc** object. 



回答5:


Simplest reason can be, not adding silent renew url as a redirect url in identity server configuration.

In your identity server database, redirect urls for your clients should be like this

redirectUrls: [http://localhost:4200/assets/silentrefresh, http://localhost:4200/auth-callback]


来源:https://stackoverflow.com/questions/48778603/silent-refresh-not-working-with-oidc-client-in-angular-5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!