토큰이란 무엇인가?
불투명 토큰을 소개하기 전에, 토큰이 무엇인지 이해하는 것이 중요합니다:
토큰은 당사자 간에 안전한 정보를 나타내고 전송하는 데 사용되며, 인터넷에서 발생하는 대부분의 인증 (Authentication) 및 권한 부여 (Authorization) 프로세스를 지원합니다. 웹 서비스에서 가장 인기 있는 두 가지 유형의 토큰은 JSON 웹 토큰 (JSON Web Token, JWT) 와 불투명 토큰입니다.
불투명 토큰이란 무엇인가?
불투명 토큰은 액세스할 수 없는 독점 형식의 토큰으로, 일반적으로 서버의 지속적인 저장소에 있는 정보에 대한 식별자를 포함합니다.
불투명 토큰은 토큰이 취할 수 있는 한 형태이며, 액세스 토큰 과 리프레시 토큰 은 불투명 토큰으로 존재할 수 있습니다. 불투명 토큰의 형식은 발급자 (issuer)에 의해 결정되며, 일반적으로 데이터베이스에서 특정 정보를 검색하고 식별하는 데 사용되는 숫자 및/또는 문자 문자열입니다. 다음은 불투명 토큰의 예입니다:
M-oxIny1RfaFbmjMX54L8Pl-KQEPeQvF6awzjWFA3iq
반면에, JWT는 또 다른 일반적인 토큰 형식입니다. 이는 모든 클레임과 정보를 포함하는 JSON 문자열로, 발급자의 서명이 함께 포함됩니다. 기본적으로 암호화되어 있지 않지만, JSON 웹 암호화 (JSON Web Encryption, JWE) 표준을 사용하여 암호화할 수 있습니다. JWT는 일반적으로 암호화되어 있지 않지만, 서명이 존재함으로써 토큰 내용의 무결성을 보장하여 JWT 내부 데이터에 대한 완전한 신뢰를 제공합니다.
JWT와 달리, 보호된 리소스에서 직접적으로 유효성을 검증할 수 있는 모든 정보를 포함하는 JWT와 달리, 불투명 토큰은 리소스에 의해 직접적으로 검증될 수 없습니다. 대신, 불투명 토큰의 발급자 (보통 인증 서버 (Authorization server) )에 의해 검증이 필요합니다. 이 검증 과정은 일반적으로 토큰 인트로스펙션 (Token introspection) 이라고 합니다.
JWT란 무엇인가?
불투명 토큰과 대조적으로, JWT는 구조화되고 읽을 수 있는 형식으로 정보를 전달하는 자체 포함, 상태 비저장 토큰입니다.
JWT는 세 부분으로 구성됩니다: header
, payload
, signature
, 각각은 Base64URL로 인코딩됩니다.
다음은 JWT의 예입니다:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
header
는 토큰의 유형과 서명에 사용된 알고리즘에 대한 정보를 포함합니다. 예를 들어,{"alg": "HS256", "typ": "JWT"}
.payload
섹션은 사용자 또는 권한 부여에 대한 정보 조각인 클레임을 포함합니다. 사용자 ID, 만료 시간, 스코프와 같은 정보가 포함될 수 있습니다. 이 데이터는 인코딩되어 있지만 암호화되어 있지 않기 때문에, 토큰을 가진 누구나 클레임을 볼 수 있지만 서명을 무효화하지 않고는 변경할 수 없습니다. 사양 및 권한 부여 서버 구성에 따라 다양한 클레임이 페이로드에 포함될 수 있습니다. 이는 토큰의 자체 포함 특성을 부여합니다. 예를 들어,{"sub": "1234567890", "name": "John Doe", "iat": 1516239022}
.signature
는 헤더, 페이로드, 비밀 키를 지정된 알고리즘으로 결합하여 생성됩니다. 이 서명은 토큰의 무결성을 검증하고 변조되지 않았음을 보장하는 데 사용됩니다.
JWT는 클라이언트 또는 서비스가 권한 부여 서버와 상호 작용할 필요 없이 로컬에서 검증할 수 있기 때문에 일반적으로 사용됩니다. 이는 여러 서비스가 토큰의 진위성을 독립적으로 검증해야 하는 분산 시스템에서 특히 효율적입니다.
그러나 이러한 편리함은 토큰의 클레임이 과도하게 노출되지 않도록 보장해야 하는 책임도 따릅니다. 토큰에 접근할 수 있는 누구나 클레임을 볼 수 있기 때문입니다. 또한, JWT는 일반적으로 수명이 짧으며, 만료 시간이 토큰의 클레임에 포함되어 있어 토큰이 무기한으로 유효하지 않도록 보장합니다.
불투명 액세스 토큰 검증
불투명 액세스 토큰은 검증을 위해 권한 부여 서버로 다시 전송하여 검증됩니다. 권한 부여 서버는 발급된 토큰의 상태를 유지하며 내부 저장소를 기반으로 토큰의 유효성을 결정할 수 있습니다.
- 클라이언트는 권한 부여 서버에 액세스 토큰을 요청합니다.
- 권한 부여 서버는 불투명 토큰을 발급합니다.
- 클라이언트는 헤더에 불투명 토큰을 포함하여 리소스 액세스 요청을 보냅니다.
- 리소스 제공자는 토큰 검증을 위해 권한 부여 서버에 토큰 인트로스펙션 요청을 보냅니다.
- 권한 부여 서버는 토큰 정보를 응답합니다.
JWT 액세스 토큰 검증 (오프라인)
JWT 액세스 토큰은 클라이언트 또는 토큰의 공개 키에 접근할 수 있는 서비스에 의해 오프라인으로 검증될 수 있습니다.
- 리소스 제공자는 OpenID Connect (OIDC) 디스커버리 (Discovery) 에서 권한 부여 서버의 공개 키를 미리 가져옵니다. 공개 키는 토큰의 서명을 검증하고 무결성을 보장하는 데 사용됩니다.
- 클라이언트는 권한 부여 서버에 액세스 토큰을 요청합니다.
- 권한 부여 서버는 JWT 토큰을 발급합니다.
- 클라이언트는 헤더에 JWT 토큰을 포함하여 리소스 액세스 요청을 보냅니다.
- 리소스 제공자는 권한 부여 서버에서 얻은 공개 키를 사용하여 JWT 토큰을 디코딩하고 검증합니다.
- 리소스 제공자는 토큰의 유효성에 따라 액세스를 허용합니다.
OIDC에서의 사용 사례
OIDC ( OpenID Connect (OIDC) )의 맥락에서, 불투명 토큰과 JWT는 서로 다른 목적을 가지고 있으며, 서로 다른 시나리오에서 사용됩니다.
불투명 토큰
- 사용자 프로필 검색:
기본적으로, 클라이언트가 리소스를 지정하지 않고 openid
스코프를 포함하여 액세스 토큰을 요청할 때, 권한 부여 서버는 불투명 액세스 토큰을 발급합니다. 이 토큰은 주로 OIDC /oidc/userinfo
엔드포인트에서 사용자 프로필 정보를 검색하는 데 사용됩니다. 불투명 액세스 토큰을 포함한 요청을 받으면, 권한 부여 서버는 내부 저장소를 확인하여 관련 권한 부여 정보를 검색하고 토큰의 유효성을 검증한 후 사용자 프로필 세부 정보를 응답합니다.
- 리프레시 토큰 교환:
리프레시 토큰은 클라이언트와 권한 부여 서버 간에만 교환되도록 설계되었으며, 리소스 제공자와 공유될 필요가 없습니다. 따라서 리프레시 토큰은 일반적으로 불투명 토큰으로 발급됩니다. 현재 액세스 토큰이 만료되면, 클라이언트는 불투명 리프레시 토큰을 사용하여 새로운 액세스 토큰을 얻을 수 있으며, 사용자를 다시 인증하지 않고도 지속적인 액세스를 보장합니다.
JWTs
- ID 토큰:
OIDC에서 ID 토큰은 사용자의 정보를 포함하고 사용자를 인증하는 데 사용되는 JWT입니다. 일반적으로 액세스 토큰과 함께 발급되며, 클라이언트가 사용자의 신원을 확인할 수 있도록 합니다. 예를 들어:
// ID 토큰의 디코딩된 페이로드
{
"iss": "<https://auth.wiki>",
"sub": "1234567890",
"aud": "client_id",
"exp": 1630368000,
"name": "John Doe",
"email": "[email protected]",
"picture": "<https://example.com/johndoe.jpg>"
}
클라이언트는 ID 토큰을 검증하여 사용자의 신원을 확인하고 개인화 또는 권한 부여 목적으로 사용자 정보를 추출할 수 있습니다. ID 토큰은 일회용으로만 사용되며 API 리소스 권한 부여에 사용되어서는 안 됩니다.
- API 리소스 액세스 (액세스 토큰 사용):
클라이언트가 특정 리소스 인디케이터 (Resource indicator) 와 함께 액세스 토큰을 요청할 때, 권한 부여 서버는 해당 리소스에 액세스하기 위한 JWT 액세스 토큰을 발급합니다. JWT는 리소스 제공자가 클라이언트의 액세스를 승인하는 데 사용할 수 있는 클레임을 포함합니다. 예를 들어:
// JWT 액세스 토큰의 디코딩된 페이로드
{
"iss": "<https://auth.wiki>",
"sub": "1234567890",
"aud": "<https://api.example.com>",
"scope": "read write",
"exp": 1630368000
}
리소스 제공자는 클레임을 확인하여 요청을 검증할 수 있습니다:
iss
: 토큰이 신뢰할 수 있는 권한 부여 서버에 의해 발급되었음을 확인합니다.sub
: 토큰과 관련된 사용자를 식별합니다.aud
: 토큰이 특정 리소스를 대상으로 하고 있음을 보장합니다.scope
: 사용자에게 부여된 권한을 검증합니다.