You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS Amplify Auth+Cognito的JWT id_token缺失nonce/at_hash问题求助

解决Amplify Authenticator隐式流中id_token缺失at_hash和nonce的问题

针对你想用Amplify Auth实现无缝SSO隐式流,却遇到id_token缺少at_hash和nonce的问题,我来给你详细的解决方案——这两个需求都是可以实现的:

一、让id_token包含at_hash声明

at_hash是OIDC隐式流的标准声明之一,它的缺失是因为你的Amplify OAuth配置没有正确指定隐式流的响应类型。你只需要调整OAuth配置,确保responseType包含token和id_token即可:

  1. 更新你的aws-exports.js或者Amplify初始化配置:
const awsconfig = {
  // ...其他原有配置
  oauth: {
    domain: 'your-cognito-domain.auth.region.amazoncognito.com',
    scope: ['openid', 'email', 'profile'], // 必须包含openid(OIDC核心要求)
    redirectSignIn: '你的认证应用回调URL',
    redirectSignOut: '你的认证应用退出URL',
    responseType: 'token id_token' // 关键:指定隐式流的响应类型
  }
};

当你设置了这个responseType后,Cognito会识别这是隐式流请求,自动计算并在id_token中添加at_hash声明(它是access_token的哈希值片段)。

二、传入nonce并让它出现在id_token中

Amplify支持在认证请求中传入nonce,但需要手动在登录请求中传递这个参数,而不是依赖Authenticator组件的默认行为。步骤如下:

  1. 生成一个随机的nonce值(用于防止重放攻击),并存储在本地(比如localStorage)
  2. 在调用Auth.signIn()或者Auth.federatedSignIn()时,将nonce作为参数传入
  3. 拿到id_token后,验证其中的nonce和你存储的是否一致

三、修改后的完整代码实现

结合上面两点,我调整了你的Login组件,同时加入了无缝SSO的逻辑(自动检测已有会话并跳转):

import React, { useEffect } from 'react';
import { Authenticator, ConfirmSignIn, SignIn } from 'aws-amplify-react';
import Amplify, { Auth } from 'aws-amplify';
import awsconfig from './aws-exports';

// 覆盖OAuth配置,确保响应类型正确
awsconfig.oauth.responseType = 'token id_token';
Amplify.configure(awsconfig);

const getSearchParams = () => window.location.search.substr(1);
const getValueFromSearchParam = (key) => new URLSearchParams(getSearchParams()).get(key);
const getRedirectUri = () => {
  const redirect_uri = getValueFromSearchParam('redirect_uri');
  return redirect_uri ? decodeURI(redirect_uri) : null;
};

// 生成随机nonce的工具函数
const generateNonce = () => {
  return Math.random().toString(36).slice(2, 18); // 生成16位随机字符串
};

const Login = () => {
  // 组件挂载时检查已有会话,实现无缝SSO
  useEffect(() => {
    Auth.currentAuthenticatedUser({ bypassCache: false })
      .then(() => handleSignedIn())
      .catch(() => {
        // 用户未登录,生成并存储nonce
        const nonce = generateNonce();
        localStorage.setItem('auth_nonce', nonce);
      });
  }, []);

  const handleSignedIn = () => {
    const redirect_uri = getRedirectUri();
    const state = getValueFromSearchParam('state');
    if (!redirect_uri) throw new Error('No redirect_uri provided');

    Auth.currentSession().then(currentSession => {
      const idTokenPayload = currentSession.idToken.payload;
      const storedNonce = localStorage.getItem('auth_nonce');

      // 验证nonce一致性,防止重放攻击
      if (storedNonce && idTokenPayload.nonce !== storedNonce) {
        throw new Error('Nonce mismatch - potential replay attack!');
      }
      localStorage.removeItem('auth_nonce');

      const id_token = currentSession.idToken.jwtToken;
      const access_token = currentSession.accessToken.jwtToken;
      const redirectUrl = `${redirect_uri}#access_token=${access_token}&id_token=${id_token}&state=${state}`;
      window.location.replace(redirectUrl);
    }).catch(err => console.error(err));
  };

  const handleAuthStateChange = (state) => {
    if (state === 'signedIn') handleSignedIn();
  };

  // 自定义SignIn组件,手动传递nonce
  const CustomSignIn = (props) => {
    const handleSubmit = (e) => {
      e.preventDefault();
      const nonce = localStorage.getItem('auth_nonce');
      // 调用Auth.signIn时传入nonce参数
      Auth.signIn(props.username, props.password, { nonce })
        .then(user => props.onStateChange('signedIn', user))
        .catch(err => props.onError(err));
    };

    return <SignIn {...props} onSubmit={handleSubmit} />;
  };

  return (
    <Authenticator hideDefault={true} onStateChange={handleAuthStateChange}>
      <CustomSignIn />
      <ConfirmSignIn />
    </Authenticator>
  );
};

export default Login;

额外注意事项

  • 确保你的Cognito用户池应用客户端已经开启了隐式流(在Cognito控制台的"应用客户端设置"中,勾选"隐式授权")
  • scope必须包含openid,否则Cognito不会返回符合OIDC标准的id_token
  • 无缝SSO的实现依赖于Cognito的会话Cookie,所以你的所有客户端必须在同一个顶级域名下(或者配置了Cognito的跨域会话共享)

内容的提问来源于stack exchange,提问作者OrderAndChaos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 17:14:11