외부 SSO 제공자 사용 중인데 Discourse 로그에는 'None has already expired'라고 나옵니다 (도움 요청!)

외부 SSO 제공자로 Firebase를 사용하고 있습니다. Discourse의 관련 지침을 따랐습니다.

로그에서 다음과 같은 오류가 발생합니다:

Verbose SSO log: Started SSO Process add_groups: admin: moderator: avatar_force_update: avatar_url: bio: card_background_url: email: external_id: groups: locale: locale_force_update: logo

Verbose SSO log: Nonce has already expired add_groups: admin: moderator: avatar_force_update: avatar_url: bio: card_background_url: email: [실제 이메일]: external_id: [외부 ID]

Discourse 로그에서도 다음과 같은 내용을 확인합니다:

Verbose SSO log: Started SSO process

add_groups: 
admin: 
moderator: 
avatar_force_update: 
avatar_url: 
bio: 
card_background_url: 
email: 
external_id: 
groups: 
locale: 
locale_force_update: 
logout: 
name: 
nonce: 773cb9d08db7007c9fb833e6c5e3a701
profile_background_url: 
remove_groups: 
require_activation: 
return_sso_url: https://discouse-site/session/sso_login
suppress_welcome_message: 
title: 
username: 
website: 
location: 

그리고

Verbose SSO log: Nonce has already expired

add_groups: 
admin: 
moderator: 
avatar_force_update: 
avatar_url: 
bio: 
card_background_url: 
email: [실제 이메일]
external_id: Be06ze0v0YO7I8SArWRoUVsxJ1k1
groups: 
locale: 
locale_force_update: 
logout: 
name: [실제 이메일]
nonce: Ym05dVkyVTlOV0kwTTJVeU1UTTVNamN6TnpNd01UbG1aVEJtWkRjMFlqTmtOV1U1TmpJbWNtVjBkWEp1WDNOemIxOTFjbXc5YUhSMGNITWxNMEVsTWtZbE1rWmpiMjF0ZFc1cGRIa3VZbTl2Wnk1aGNIQWxNa1p6WlhOemFXOXVKVEpHYzNOdlgyeHZaMmx1
profile_background_url: 
remove_groups: 
require_activation: 
return_sso_url: https://discouse-site/session/sso_login
suppress_welcome_message: 
title: 
username: [실제 이메일]
website: 
location:  

현재 사이트 사용이 불가능한 상태이므로 Discourse 팀의 도움이 필요합니다.

James

이 분야에 전문가라기보다는, 시계가 정확한지 확인해 보는 것이 좋을 것 같습니다.

제안해 주셔서 감사합니다. 하지만 시계가 문제인 것 같지는 않습니다. Discourse 서버와 nonce가 생성되는 서버의 시간이 동일합니다.

이 문제를 좀 더 명확히 하기 위해 return URL을 생성하는 방식을 공유합니다:

   public String generateSSORedirectURL(String nonce, String email, String uid) {

    // 리턴 페이로드 생성
    HashMap<String, String> params = new HashMap<String, String>();
    params.put("nonce", nonce);
    params.put("external_id",uid);
    params.put("email",email);
    params.put("username",email);
    params.put("require_activation","false");
    params.put("name",email);
    params.put("return_sso_url","https://discourse-site/session/sso_login");
    log.info("params {}", params);

    // 리턴 페이로드 준비
    String encodedParams = params.keySet().stream()
        .map(key -> key + "=" + encodeValue(params.get(key)))
        .collect(Collectors.joining("&"));
    log.info("encoded parameters {}", encodedParams);

    String returnPayload = Base64.getEncoder().encodeToString(encodedParams.getBytes());
    log.info("return Payload {}", returnPayload);

    // 페이로드에 대한 hmacSha256 서명 계산
    byte[] hmacSha256 = calcHmacSha256(ssoSecret.getBytes(), returnPayload.getBytes());
    log.info("hmacSha256 sig {}", hmacSha256);
    
    String hmacSha265Hex = String.format("%x", new BigInteger(1, hmacSha256));
    log.info("hmacSha256, sig in Hex {}", String.format("%x", new BigInteger(1, hmacSha256)));

    HashMap<String, String> params2 = new HashMap<String, String>();
    params2.put("sig", hmacSha265Hex);
    params2.put("sso", returnPayload);
    log.info("params2 {}", params);

    String encodedParams2 = params2.keySet().stream()
        .map(key -> key + "=" + encodeValue(params2.get(key)))
        .collect(Collectors.joining("&"));
    log.info("encoded parameters {}", encodedParams2);

    // 쿼리 문자열 구성 및 반환
    String queryString = forumUrl + "session/sso_login?" + encodedParams2;
    log.info("queryString {}", queryString);

    return queryString;
}

이 문제를 해결하신 적이 있으신가요? @James_Hope