【问题标题】:AWS Cognito OAuth2 with PCKE "Invalid Request" Code Challenge带有 PCKE“无效请求”代码挑战的 AWS Cognito OAuth2
【发布时间】:2021-07-12 09:19:50
【问题描述】:

我一直在尝试将 statecode_challenge 添加到我们的流程中,但由于某种原因,我继续收到来自亚马逊的 invalid_request 回复。

我跟着这个Auth0 tutorial 去了一个发球台。

  /**
   * Converts buffer to Base64 URL encoded string
   *
   * @param {Buffer} buf The buffer to convert
   * @returns {string}
   */
  private base64URLEncode(str: any): string {
    return str.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
  }

  /**
   * Generates a new code challenge
   *
   * @returns {string} The code challange string
   */
  private generateCodeChallenge(): string {
    if (!this._verifier) this._verifier = this.base64URLEncode(crypto.randomBytes(32));

    return this.base64URLEncode(crypto.createHash('sha256').update(this._verifier).digest());
  }

  /**
   * Generates the Authorization URL
   */
  public generateAuthUrl(): string {
    if (!this.config.clientId) throw new Error('Client ID is missing from configuration.');
    if (!this.config.redirectUrl) throw new Error('Redirect URI is missing from configuration.');

    if (!this._state) this._state = this.base64URLEncode(crypto.randomBytes(28));

    return `${this.config.protocol}://signin.${
      this.config.host
    }/login?response_type=code&client_id=${this.config.clientId}&redirect_uri=${
      this.config.redirectUrl
    }&scope=${this._scope.join('%20')}&state=${
      this._state
    }&code_challenge_method=S256&code_challenge=${this.generateCodeChallenge()}`;
  }

  /**
   * Verifies that the state matches
   *
   * @returns {boolean}
   */
  public verifyState(state: string): boolean {
    return this._state === state;
  }

  /**
   * Retrieves a new OAuth Authorization Grant token
   */
  public async getToken(code: string): Promise<UserAccessToken> {
    if (!this.config.clientId) throw new Error('Client ID is missing from configuration.');
    if (!this.config.redirectUrl) throw new Error('Redirect URI is missing from configuration.');

    try {
      const token = (await this.req.postform(
        `/oauth2/token`,
        {
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Cache-Control': 'no-store',
          },
        },
        {
          grant_type: 'authorization_code',
          code,
          client_id: this.config.clientId,
          code_verifier: this._verifier,
          redirect_uri: this.config.redirectUrl,
        }
      )) as UserAccessToken;

      this._userAccessToken = token;

      return token;
    } catch (err) {
      throw err;
    }
  }

在用代码交换令牌之前,一切都运行良好。我们重定向到我们托管的 UI 并成功取回代码。当我们将其换成令牌时,无论我尝试了什么,我们都会收到 invalid_request 响应。如果我删除代码挑战,一切都会按预期工作,所以我非常有信心这是导致问题的原因。

更新 1

这个函数在我们的 React 应用程序中的 useEffect 钩子内调用,如下所示:

  useEffect(() => {
    const authUrl = sdk.auth.generateAuthUrl();
    console.log(authUrl);
    if (!code) window.location.assign(authUrl);
    console.log(`New Auth URL: ${authUrl}`);
    sdk.auth
      .getToken(code as string)
      .then((token) => {
        localStorage.setItem('sdk_access_token', JSON.stringify(token));
        sdk.organizations.getUser().then((user) => {
          setUser({ ...user });
          history.push('/');
        });
      })
      .catch((err) => console.log(err));
  }, []);

两个 console.log 语句显示相同的 URL:

但在网络调试选项卡上,请求 URL 不同:

这怎么可能? window.location.href 是否以某种方式对 URL 进行了编码?

【问题讨论】:

    标签: node.js oauth-2.0 amazon-cognito


    【解决方案1】:

    据我所知,您的代码和消息看起来不错。如果您在 Cognito 中配置了 App Client Secret,这可以解释问题(Cognito 错误响应不是最好的)。

    也许可以从我的工作 Cognito 样本中尝试这些硬编码值 - 或者通过 this tool 运行您正在计算的值。这将使您知道问题是否与 PKCE 值有关:

    • 挑战:tQV5Ny5h0r5pwqpDr0OGnQWgfU4DTTniuu99HZGOOE0
    • 验证者:4ffc114e504047deb57f3e8dfeeda70d93bbfb6d8f0444c9b9b147f3872dbde24f58cbe3047d49ce9b5194fe80e0905a

    有很多库都有一些 working PKCE code 虽然我希望 Auth0 代码很好......

    【讨论】:

    • 太奇怪了。如果我对这些值进行硬编码,它就可以工作。使用您建议的工具,我的验证器和代码挑战匹配它们应该是什么。但是,如果我生成值......它会失败。将尝试进一步调试。
    • 添加了一些额外的发现。我认为这可能是浏览器以某种方式重新编码代码挑战。
    • 尝试对授权重定向中的所有查询参数和帖子中的所有表单参数使用 encodeUriComponent。也许将代码与使用 PKCE 的工作库进行比较,例如 oidc-client
    • 您的原始评论是正确的:“据我所知,您的代码和消息看起来不错”。问题在于 React 重新加载状态。我们生成了质询/验证程序,然后将用户重定向到 AWS。当他们被重定向回来时,类被重新初始化并且验证者是undefined。出于某种原因,尽管网络选项卡仍将其显示为正在发送。当我们对变量进行硬编码时,它们只是被重新初始化为相同的东西,这让我陷入了循环。
    猜你喜欢
    • 2019-08-11
    • 1970-01-01
    • 2018-01-21
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 2022-11-01
    • 2022-08-03
    相关资源
    最近更新 更多