서비스의 권한이 주어진 사용자인지 확인하는 로그인 과정에 인증이 필요하다. HTTP는 프로토콜 특성 자체가 연결을 유지시키지 않는다. 따라서 HTTP 자체로는 요청 시마다 인증을 반복해야하는 문제점이 있다. 별도 추가적인 방법을 통해 인증을 유지해야 하는데 그 중에서도 토큰
인증에 대해 얘기하려고 한다. 로그인 성공 시 서버에서 클라이언트로 토큰을 발급하고 이를 Request
시마다 Header
에 저장하여 인증/인가 시 사용한다.
토큰은 인증 유지에 사용된다. 인증 유지라는 개념은 사용자가 한번 로그인 한 이후 특정 시간 내에는 다시 로그인하지 않아도 사용자의 로그인 상태를 계속 유지시켜주는 개념이다. 인증 유지 개념이 없는 시스템이라면 사용자는 화면이 전환될 때 마다 매번 로그인을 해야 하거나 서버에서는 매번 요청에 대해 사용자가 이 요청을 처리할 수 있는 사용자인지에 대해 데이터베이스로부터 정보를 읽어와 확인해야 한다.
토큰이 탈취된 상황에 취약하다. 서버에서는 이미 발급된 토큰에 대해 아무런 제어도 불가하기 때문에, 유효기간이 지나기 전까지 특정 정보
에 접근이 가능하다. 이러한 취약점을 보완하기 위한 것이 AccessToken
과 RefreshToken
개념이다. 기존의 AccessToken
의 유효기간을 짧게 하고 RefreshToken
이라는 새로운 토큰을 발급하면 AccessToken
을 탈취당해도 상대적으로 피해를 줄일 수 있다.
aws에서는 cognito
라는 서비스를 통해 인증과 권한 부여 그리고 사용자 관리를 제공한다. Cognito의 구성 요소인 User Pool
은 사용자 관리에 중점을 두고 있고, Identity Pool
은 자격 증명의 관리와 AWS 리소스에 대한 권한 부여에 중점을 둔다.
애플리케이션에서 사용자는 User Pool을 통해 인증하고, Identity Pool에서는 해당 사용자에게 AWS 자격 증명을 제공. Cognito User Pool과 Cognito Identity Pool을 사용하여 사용자를 인증하고, 인증된 사용자에게 Identity Pool을 통해 토큰을 얻어오는 시나리오
import { CognitoIdentity, CognitoIdentityServiceProvider } from 'aws-sdk';
const region = 'your-region';
const userPoolId = 'your-user-pool-id';
const clientId = 'your-client-id';
const identityPoolId = 'your-identity-pool-id';
const username = 'user@example.com';
const password = 'user-password';
// AWS SDK 인스턴스 생성
const identity = new CognitoIdentity({ region });
const serviceProvider = new CognitoIdentityServiceProvider({ region });
// 사용자 풀(User Pool)에 대한 로그인 정보 설정
const authData = {
Username: username,
Password: password,
};
const authDetails = new CognitoIdentityServiceProvider.AuthenticationDetails(authData);
const userData = {
Username: username,
Pool: new CognitoIdentityServiceProvider.CognitoUserPool({
UserPoolId: userPoolId,
ClientId: clientId,
}),
};
const cognitoUser = new CognitoIdentityServiceProvider.CognitoUser(userData);
// 사용자 풀(User Pool)에서 로그인
cognitoUser.authenticateUser(authDetails, {
onSuccess: (session) => {
console.log('Authentication successful. Getting OpenID token...');
// 사용자가 로그인한 세션을 사용하여 Identity Pool에서 OpenID 토큰 얻기
const loginMap = {
[`cognito-idp.${region}.amazonaws.com/${userPoolId}`]: session.getIdToken().getJwtToken(),
};
const getOpenIdTokenParams: CognitoIdentity.GetOpenIdTokenForDeveloperIdentityInput = {
IdentityPoolId: identityPoolId,
Logins: loginMap,
};
identity.getOpenIdTokenForDeveloperIdentity(getOpenIdTokenParams, (err, data) => {
if (err) {
console.error('Error getting OpenID token:', err);
} else {
console.log('Received OpenID token:', data);
// OpenID 토큰을 사용하여 Identity Pool에서 AWS 자격 증명 얻기
const getCredentialsParams: CognitoIdentity.GetCredentialsForIdentityInput = {
IdentityId: data.IdentityId || '',
Logins: loginMap,
};
identity.getCredentialsForIdentity(getCredentialsParams, (credErr, credData) => {
if (credErr) {
console.error('Error getting AWS credentials:', credErr);
} else {
console.log('Received AWS credentials:', credData);
}
});
}
});
},
onFailure: (err) => {
console.error('Authentication failed:', err);
},
newPasswordRequired: (userAttributes, requiredAttributes) => {
console.log('New password required.');
},
});
https://docs.aws.amazon.com/ko_kr/cognitoidentity/latest/APIReference/Welcome.html