Node.js에서 AWS Cognito의 비밀 해시 계산

Amplify 및 Cognito 클라이언트 라이브러리는 클라이언트 시크릿이 있는 사용자 풀을 지원하지 않지만 이는 클라이언트 시크릿이 브라우저에 노출되지 않도록 하기 위한 것일 뿐입니다. 그러나 이것이 Node.js에서 전체 Cognito API를 사용할 수 없다는 의미는 아닙니다.

최근에 Node.js Lambda 함수에서 Cognito API를 사용하여 가입 흐름을 사용자 지정하려고 했지만 사용자를 가입하려고 할 때 계속 오류SecretHash does not match for the client가 발생했습니다. 약간의 파고는 나를 Cognito documentation 로 이끌었습니다. 여기에는 Java의 몇 가지 예제 코드가 포함되어 있지만 그렇지 않은 경우에는 비밀 해시를 생성하기 위해 일부 의사 코드만 포함되어 있습니다.

The SecretHash value is a Base 64-encoded keyed-hash message authentication code (HMAC) calculated using the secret key of a user pool client and username plus the client ID in the message. The following pseudocode shows how this value is calculated. In this pseudocode, + indicates concatenation, HMAC_SHA256 represents a function that produces an HMAC value using HmacSHA256, and Base64 represents a function that produces Base-64-encoded version of the hash output.

Base64 ( HMAC_SHA256 ( "Client Secret Key", "Username" + "Client Id" ) )


HMAC는 두 당사자가 키를 알고 있는지 확인하고 생성할 수 있는 특별한 종류의 해시입니다. 이는 서명된 쿠키, JWT 및 웹후크 확인과 같은 작업에 자주 사용됩니다. 우리의 앱과 Cognito만이 클라이언트 암호를 알아야 하고 HTTPS가 이미 요청을 암호화하고 있기 때문에 이는 AWS가 사용하는 간단한 확인 방법으로 의미가 있습니다.

Node.js에 crypto 모듈이 내장되어 있다는 것을 알고 있습니다. 과거에 SHA-256 해시를 생성하는 데 사용했지만 특정 키를 사용한 적이 없었습니다. crypto docs을 파헤칠 시간입니다! 다행스럽게도 Node.jscrypto 모듈은 이전에 참조한 Cognito 설명서의 Java 구현과 유사한 "빌더"패턴을 따릅니다.

노드에서 SHA-256 알고리즘을 사용하여 HMAC 값을 생성하는 방법은 다음과 같습니다.

import { createHmac } from 'crypto';

// create the hmac with the sha256 algorithm and a secret key
const hasher = createHmac('sha256', 'a secret');

// add the value we want to hash
hasher.update('value to hash');

// get the hashed value as base64
let output = hasher.digest('base64');

SecretHash 를 생성하는 데 필요한 곳에 사용자 풀 값을 연결할 수 있습니다. 예를 들어 SignUp 방법을 사용하고 있지만 ConfirmSignUp , ForgotPassword , ConfirmForgotPasswordResendConfirmationCode (아마도 그 이상)에 대해 동일합니다. 또한 Lambda Node.js 런타임에 포함된 JavaScript v2용 AWS SDK를 사용하고 있지만 비밀 해시는 SDK의 v3에 대해 동일한 방식으로 생성됩니다.

import { createHmac } from 'crypto';
import { CognitoIdentityServiceProvider } from 'aws-sdk';

// grab all the constant variables from the user pool
const CLIENT_SECRET = process.env.COGNITO_CLIENT_SECRET;
const CLIENT_ID = process.env.COGNITO_CLIENT_ID;
const USER_POOL_ID = process.env.COGNITO_USER_POOL_ID;

function signUp(username, password, attributes) {
  const cognito = new CognitoIdentityServiceProvider();

  const hasher = createHmac('sha256', CLIENT_SECRET);
  // AWS wants `"Username" + "Client Id"`
  hasher.update(`${username}${CLIENT_ID}`);
  const secretHash = hasher.digest('base64');

  return cognito.signUp({
    UserPoolId: USER_POOL_ID,
    ClientId: CLIENT_ID,
    UserName: username,
    Password: password,
    SecretHash: secretHash,
    UserAttributes: [
      // some attributes as an example
      { Name: 'email', Value: attributes.email },
      { Name: 'given_name', Value: attributes.firstName },
      { Name: 'family_name', Value: attributes.lastName },
    ]
  }).promise();
}


AWS Cognito는 매우 매력적인 요금 모델과 애플리케이션에 대해 원하는 모든 유형의 인증을 구축할 수 있는 많은 기능을 갖추고 있지만 채택을 복잡하게 만드는 단점이 상당히 많습니다. 바라건대 이것은 당신이 파는 데 몇 시간을 절약합니다.

AWS Cognito와 씨름하려고 시도한 다른 문제가 있으면 댓글로 알려주십시오.

좋은 웹페이지 즐겨찾기