为什么一段时间后IdentityServer 4代码流得到invalid_grant响应?

问题描述

我正在为我的角度应用程序使用identityserver4代码流。我正在使用angular-oauth2-oidc库。

我的配置是这样的:

   OauthConfig: AuthConfig = {
        issuer: 'http://mydomain.identityserver4',requireHttps: false,responseType: "code",redirectUri: window.location.origin + '/index.html',clientId: 'dev.code.flow',scope: 'openid profile offline_access my.api',logoutUrl: window.location.origin + '/index.html',postlogoutRedirectUri: window.location.origin + '/index.html'
    }

  private configureOauth(){
    this.oauthService.configure(OauthConfig);
    this.oauthService.tokenValidationHandler = new JwksValidationHandler();
    this.oauthService.loaddiscoveryDocumentAndLogin();
    this.oauthService.setupAutomaticSilentRefresh();
  }

登录应用程序后,库每5分钟发送一次刷新令牌请求。我可以在chrome开发人员工具中看到这一点。

但是几个小时后,令牌刷新请求出现400(错误请求)错误错误消息是error: "invalid_grant"

这可能是什么原因?

解决方法

根据OAuth2.0协议,刷新令牌和访问令牌都具有一定的生存期。

好像您的刷新令牌在几个小时后就过期了。要解决此问题,您可以

  • 延长刷新令牌的寿命(通常它们使用寿命长,应该安全处理)
  • 要求用户再次登录。
  • 可以使用滑动到期模式。

这来自IdentityServer4文档(link):

AbsoluteRefreshTokenLifetime:中的刷新令牌的最大生存期 秒。默认值为2592000秒/ 30天。零允许刷新 与RefreshTokenExpiration =仅滑动一起使用的令牌 传递了SlidingRefreshTokenLifetime后过期。

您可以在IdentityServer4的客户端配置中配置刷新令牌超时。

以下是我用来将用户重定向到登录页面的方法:

setupAutomaticLogoutInCaseOfTokenExpiry() {
    if (!this.oauthService.events) {
      return;
    }

    this.oauthService.events.subscribe((x: any) => {
      if (x.type === 'token_refresh_error') {
        // In case of internet connectivity
        if (x.reason && x.reason.error && x.reason.error.error === 'invalid_grant' &&
            x.reason.error.error_reason === 'refresh_token_not_found') {
          this.oauthService.logOut(true);
          (window as any).removeAllListeners();
          this.router.navigateByUrl(`/${Constants.PageUrls.Login}`);
        } else {
          // In case of no internet connectivity
          this.oauthService.stopAutomaticRefresh();
          const rereshTimeout = setTimeout(() => {
            this.oauthService.refreshToken().then(() => {
              this.oauthService.setupAutomaticSilentRefresh();
              clearTimeout(rereshTimeout);
            })
            .catch(() => {
              clearTimeout(rereshTimeout);
            });
          },5000);
        }
      }
    });
}