Skip to content

Latest commit

 

History

History
202 lines (138 loc) · 20.4 KB

File metadata and controls

202 lines (138 loc) · 20.4 KB
source https://www.keycloak.org/securing-apps/jwt-authorization-grant
keycloak_version 26.6.2
translated 2026-06-03
category securing-apps

JWT 인가 그랜트(JWT Authorization Grant)

원문 제목(EN): JWT Authorization Grant 원문: https://www.keycloak.org/securing-apps/jwt-authorization-grant

이 가이드는 JWT 베어러 토큰(JWT Bearer Token)이 Keycloak에서 인가 그랜트(authorization grant)로 어떻게 사용될 수 있는지를 설명합니다. 이 기능은 클라이언트가 인가 서버(authorization server)에서 직접 사용자 승인 단계 없이 기존 신뢰 관계(trust relationship)를 활용하여 액세스 토큰을 요청하고자 할 때 JWT 어설션(assertion)을 전송할 수 있게 해줍니다. 어설션은 JWT의 클레임(claim)과 서명(signature)만으로 검증됩니다. 신뢰 관계는 일반적으로 다른 ID 제공자(Identity Provider) 서버(다른 OIDC 서버)를 가리키며, 크로스 도메인(cross-domain) 또는 크로스 렐름(cross-realm) 액세스 토큰을 획득할 수 있게 해줍니다. 이런 의미에서, 토큰 교환(token exchange) V1의 외부-내부 요청(external to internal request)과 유사합니다(자세한 내용은 토큰 교환 설정 및 사용 참고).

JWT 인가 그랜트는 두 가지 RFC에 의해 규정됩니다.

  • OAuth 2.0 클라이언트 인증 및 인가 그랜트를 위한 어설션 프레임워크(RFC 7521). 그랜트로 어설션을 사용하기 위한 일반 프레임워크.
  • OAuth 2.0 클라이언트 인증 및 인가 그랜트를 위한 JSON 웹 토큰(JWT) 프로파일(RFC 7523). JWT 어설션에 대한 구체적인 내용.

요약하면, JWT 인가는 OAuth 2.0 RFC 6749에 정의된 OAuth 확장 그랜트(extension grant)로, 토큰 엔드포인트(token endpoint)에 전송됩니다. grant_type 요청 파라미터는 반드시 urn:ietf:params:oauth:grant-type:jwt-bearer여야 합니다. assertion은 서버에서 검증될 일부 클레임을 포함하는 단일 JWT여야 합니다. scope 파라미터는 선택 사항이며, OAuth 2.0이 설명하고 다른 그랜트에 대해 Keycloak이 관리하는 것과 동일한 의미를 유지합니다. 어설션 토큰이 인가에 유효하면, 인가 엔드포인트와의 어떤 상호작용도 없이 클라이언트에게 액세스 토큰이 반환됩니다.

Keycloak의 신뢰 관계는 ID 제공자(Identity Provider)로 정의됩니다. 현재 두 가지 ID 제공자 유형이 JWT 인가 그랜트를 관리할 수 있습니다:

  1. OpenID Connect v1.0 / Keycloak OpenID Connect
  2. JWT Authorization Grant

OpenID Connect v1.0(이전 유형의 확장인 Keycloak OpenID Connect 포함)은 외부 OpenID 제공자(OP, OpenID Connect 사양을 구현하는 OAuth 2.0 인증 서버)와의 신뢰 관계를 정의하는 데 사용할 수 있습니다. 이것이 일반적인 선택입니다. 수신된 어설션은 제공자 설정을 사용하여 클레임과 서명 측면에서 JWT 토큰을 검증합니다.

JWT Authorization Grant는 Keycloak에서 일반 신뢰 관계를 나타내는 새로운 유형의 ID 제공자입니다. 이전 유형과 유사하게, 설정을 통해 어설션을 검증하고 JWT 인가 그랜트를 사용하여 액세스 토큰을 얻을 수 있습니다.

Keycloak은 어설션에서 sub 클레임이 외부 제공자의 사용자 식별자여야 합니다. Keycloak 사용자는 사전에 ID 제공자와 연결(link)되어 있어야 합니다. 이를 통해 외부 ID와 내부 사용자 ID 간에 연결이 형성됩니다.

Keycloak이 어설션에 대해 수행하는 정확한 처리 과정은 다음과 같습니다(어설션 JWT에서 요구되는 조건에 대한 자세한 내용은 앞서 언급한 RFC를 참고하십시오):

  1. 요청자 클라이언트는 JWT 인가 그랜트를 허용하도록 설정되어 있어야 합니다.
  2. iss(issuer) 클레임은 ID 제공자(issuer 설정 옵션)를 식별해야 합니다.
  3. ID 제공자는 JWT 인가 그랜트를 허용하도록 설정되어 있어야 하며, 클라이언트는 이 IdP와 그랜트를 교환할 수 있도록 설정되어 있어야 합니다.
  4. sub(subject) 클레임은 Keycloak에서 사용자를 식별해야 합니다. 앞서 언급한 것처럼, sub 클레임은 외부 제공자에서의 사용자 ID여야 합니다. Keycloak의 사용자는 ID 제공자와 연결되어 있어야 합니다. 연결 정보가 최종적으로 Keycloak에서 사용자를 찾습니다.
  5. aud(audience) 클레임은 Keycloak 서버(issuer 또는 토큰 엔드포인트 URL)를 식별해야 합니다.
  6. exp(expiration) 클레임은 존재해야 하며 검증되어야 합니다.
  7. nbf(not before), iat(issued at), jti(JWT ID)와 같은 다른 클레임들은 존재할 수 있으며, 존재하는 경우 검증되어야 합니다.
  8. JWT는 서명되어야 하며, 서명은 Keycloak의 ID 제공자와 연관된 키로 검증되어야 합니다.

참고(NOTE): 브루트 포스 보호(brute force protection)는 일시적으로 잠긴 사용자에 대해 JWT 인가 그랜트에 적용되지 않습니다. 이 그랜트 유형은 사용자 자격 증명 기반 인증을 수행하지 않고 외부 ID 제공자가 발급한 어설션에 의존하기 때문에, Keycloak 사용자 자격 증명에 대한 브루트 포스 공격으로 손상될 수 없습니다.

설정(Configuration)

기밀 클라이언트(confidential client)만 JWT 인가 그랜트를 요청할 수 있습니다. 클라이언트가 이러한 그랜트를 전송할 수 있도록 하려면, 클라이언트를 적절히 설정해야 합니다. 관리 콘솔(admin console)에서 clients → 클라이언트 선택 → Settings 탭 → Capability config 섹션으로 이동합니다.

  1. JWT Authorization Grant 기능을 활성화합니다.
  2. Allowed Identity Providers for JWT Authorization Grant 옵션에서, 이 클라이언트가 인가 그랜트에 사용할 수 있는 모든 ID 제공자를 선택합니다.

JWT Authorization Grant를 위한 클라이언트 설정 Figure 1. JWT Authorization Grant를 위한 클라이언트 설정

참고(NOTE): Advanced 탭의 OpenID Connect Compatibility Modes 섹션에서, Custom audience mapping 설정 옵션을 통해 개별 ID 제공자에 대해 특정 커스텀 유효 대상(audience)을 설정할 수 있습니다. 맵의 키는 ID 제공자 별칭(alias)이며, 값은 해당 제공자에서 허용될 커스텀 대상입니다. 이 동작은 표준에서 다루지 않으며, 주요 보안 영향을 미칠 수 있음에 유의하십시오.

ID 제공자(소개에서 언급한 두 유형 모두)도 어설션을 검증하는 관계를 설정하도록 설정해야 합니다. Identity providers → OIDC 또는 JWT 제공자 선택 → Settings 탭 → Authorization Grant Settings 섹션으로 이동합니다.

  1. JWT Authorization Grant 스위치 옵션을 활성화합니다.
  2. 나머지 옵션들을 원하는 대로 설정합니다.
    • Allow assertion reuse: 기본적으로 Keycloak은 일회성 어설션만 허용하며(재사용은 허용되지 않음), jti 클레임이 JWT에 존재해야 합니다(토큰의 고유 식별자).
    • Max allowed assertion expiration: 서버가 어설션에서 허용하는 최대 만료 시간. 기본값은 5분.
    • Assertion signature algorithm: 어설션에 유효한 서명 알고리즘. 지정하지 않으면 모든 서명이 유효합니다.
    • Allowed clock skew: ID 제공자 토큰을 검증할 때 허용되는 클록 스큐(clock skew, 초 단위). 기본값은 0입니다.
    • Limit access token expiration: 활성화하면, JWT 어설션의 만료 시간이 계산된 액세스 토큰 만료 시간보다 짧은 경우에만 액세스 토큰 수명이 JWT 어설션의 만료로 제한됩니다.

참고(NOTE): OpenID Connect ID 제공자 유형에는 Advance settings 섹션에 Allows Client ID as audience for assertions라는 추가 설정 스위치가 있습니다. 이 옵션이 활성화되면, 제공자 설정의 Client ID가 Federated 클라이언트 인증 및 JWT 인가 그랜트에 사용되는 어설션의 유일한 유효 대상으로 설정됩니다. 클라이언트 ID는 각 사양에서 정의된 token-url/issuer-url 대신 사용됩니다. 이 동작은 어떤 표준에도 다루어지지 않습니다.

JWT Authorization Grant를 위한 ID 제공자 설정 Figure 2. JWT Authorization Grant를 위한 OIDC ID 제공자 설정

이전의 특정 옵션들 외에, 두 ID 제공자 유형 모두 어설션 및 서명 검증과 관련된 일부 기본 설정이 필요합니다.

  • Issuer: 어설션의 발급자(issuer). 필수.
  • Use JWKS URL: 어설션 서명을 검증할 키를 얻기 위해 JWKS 엔드포인트 URL을 사용할지 여부. 비활성화된 경우, 키는 관리자가 수동으로 제공해야 합니다. 권장값은 On입니다.
  • JWKS URL: 서명 키를 다운로드하기 위한 URL. Use JWKS URL이 활성화된 경우 필수.
  • Validating public key id: 어설션 서명 검증을 위한 고정 kid. 이 옵션은 구성된 공개 키로만 서명을 검증하려면 비워 둘 수 있습니다. 이 옵션은 Use JWKS URL이 비활성화되고 검증 키가 PEM 형식의 고정 키로 정의된 경우에만 지정할 수 있습니다.
  • Validating public key: 외부 IdP 서명을 검증하는 데 사용해야 하는 PEM 또는 JWKS 형식의 공개 키. Use JWKS URL이 비활성화된 경우 필수.

경고(WARNING): JWT 인가 그랜트가 OIDC ID 제공자와 함께 설정된 경우, 토큰 엔드포인트로 전송되는 JWT 토큰의 서명은 항상 검증됩니다. OIDC ID 제공자 옵션 Validate Signatures는 JWT 인가 그랜트에서는 무시되며, 이 옵션은 이 OIDC ID 제공자로 사용자를 인증하는 동안 OIDC ID 제공자에서 가져온 토큰의 서명 검증에만 사용됩니다.

예시(Examples)

다음은 토큰 엔드포인트로 전송되는 JWT 인가 그랜트 요청의 예시입니다. 클라이언트 ID는 test-client이며, 비밀(secret)로 인증하고, https://jwt-idp.example.com을 issuer로 하는 ID 제공자에 대해 JWT 인가 그랜트를 허용하도록 설정되어 있습니다.

POST /realms/demo/protocol/openid-connect/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Accept: application/json

client_id=test-client&
client_secret=XXXXX&
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&
assertion=eyJhbGci[...redacted...].eyJpc3Mi[...redacted...].J9l-ZhwP[...redacted...]

중요한 파라미터는 assertion입니다. 다음은 어설션 내부에서 사용되는 JWT 클레임 셋(JWT Claims Set)을 생성하기 위해 인코딩할 수 있는 JSON 객체의 예시입니다.

{
  "jti":"abcd1234-5678-efgh-ijkl-9012mnopqrst",
  "iss":"https://jwt-idp.example.com",
  "sub":"b3588c7e-14cb-46a9-9387-28adfd82f7a4",
  "aud":"https://keycloak.server/realms/demo",
  "iat":1764839065,
  "exp":1764839365,
  "other-claim":true
}

클레임에는 ID 제공자를 식별하는 iss, 제공자와의 연결을 통해 Keycloak 사용자를 찾는 데 사용되는 외부 시스템의 사용자 ID가 포함된 sub, Keycloak의 issuer 또는 토큰 엔드포인트인 aud, 일회성 사용을 보장하는 jti, 필수인 exp가 포함되어야 합니다. 토큰에 다른 클레임들도 추가할 수 있습니다.

이전 JSON 예시는 서명되어야 하며, JWT 헤더는 서명에 사용된 알고리즘과 키 식별자를 지정해야 합니다. 해당 키는 서명을 검증하기 위해 ID 제공자에 올바르게 설정되어 있어야 합니다(JWKS URL을 통해 또는 수동으로).

{"alg":"ES256", "kid":"2AOACLJmd5dQ8HPrDxwpkS-83yBhrzaLWSny9wmnYcY"}

Keycloak은 요청과 어설션을 검증합니다. 모든 것이 올바르면, 응답에는 바로 사용할 수 있는 액세스 토큰이 포함됩니다.

{
  "access_token":"eyJhbG[...redacted...].eyJleH[...redacted...].RFnNEv[...redacted...]",
  "expires_in":300,
  "refresh_expires_in":0,
  "token_type":"Bearer",
  "not-before-policy":0,
  "scope":"email profile"
}

참고(NOTE): 사양 권장 사항에 따라, JWT 인가 그랜트는 리프레시 토큰(refresh token)을 발급하지 않으며 임시 세션(transient session)이 항상 생성됩니다. 액세스 토큰은 Keycloak의 인트로스펙션(introspection), 사용자 정보(user-info) 또는 다른 엔드포인트를 통해 정상적으로 사용할 수 있습니다. 만료되거나 철회 엔드포인트(revocation endpoint)에 의해 명시적으로 폐기되기 전까지 유효합니다.

JWT 인가 그랜트를 위한 유효한 토큰 획득 방법

JWT 인가 그랜트 기능은 액세스 토큰으로 교환하기 위해 이전 JWT 어설션이 필요합니다. 외부 OpenID Connect 제공자(OP)를 domaina(Keycloak의 ID 제공자를 통해 표현됨)라고 하고, JWT 인가 그랜트를 받는 Keycloak 서버를 domainb라고 합시다. domainadomainb에 유효한 어설션인 JWT를 어떤 방식으로든 발급해야 합니다.

domaina가 Keycloak이 아닌 다른 서버인 경우, 해당 초기 JWT가 어떻게 획득되는지는 알 수 없습니다. 그러나 사양은 어설션이 유효하고 액세스 토큰을 반환하기 위해 일부 처리를 강제한다는 점에 유의하십시오. 클라이언트가 domaina에서 그러한 JWT 어설션을 얻거나 생성하는 방법은 완전히 domaina 서버와 클라이언트에 달려 있습니다.

외부 ID 제공자가 다른 Keycloak 서버 또는 렐름(realm)인 경우, 표준 토큰 교환(Standard Token Exchange)을 사용하여 그러한 토큰을 얻을 수 있습니다(자세한 내용은 토큰 교환 설정 및 사용 참고). 양쪽이 모두 Keycloak 렐름인 경우, 개념을 두 가지 기본 포인트로 요약할 수 있습니다:

  1. domaina의 입장에서, domainb는 토큰 교환을 통해 제한될 수 있는 대상(audience)입니다.
  2. domainb의 입장에서, domaina는 어설션을 검증하는 데 사용되는 ID 제공자입니다. domainb의 사용자도 ID 제공자를 통해 이전에 domaina와 연결된 유효한 사용자여야 합니다.

두 Keycloak 렐름에 걸쳐 인가 체이닝(authorization chaining)을 수행하기 위한 자세한 설정은 OAuth Identity and Authorization Chaining Across Domains를 참고하십시오.

클라이언트 정책과 JWT 인가 그랜트

JWT 인가 그랜트와 관련된 새로운 조건(condition) 및 실행기(execution)가 Keycloak의 클라이언트 정책(client policies)에 추가되었습니다.

  • 조건 identity-provider-alias. 이 조건은 특정 ID 제공자 별칭(alias)을 포함하는 요청을 선택할 수 있게 해줍니다. 별칭 목록을 정의할 수 있으며, 목록에 있는 ID 제공자 중 하나가 존재하면 조건이 true로 평가됩니다. 현재 이 조건은 JWT 인가 그랜트만 관리하지만, 향후 ID 제공자를 포함하는 다른 작업으로 확장될 수 있습니다.

  • 실행기 downscope-assertion-grant-enforcer. 이 실행기는 요청된 스코프(scope)가 어설션 토큰에 포함된 스코프(JWT의 scope 클레임)를 초과하지 않도록 강제합니다. 어설션에 이미 존재하지 않는 스코프가 요청된 경우 오류가 반환됩니다. 이 실행기는 초기 어설션 JWT에서 부여된 것보다 더 많은 권한(스코프 또는 대상)을 얻지 못하도록 방지하는 데 사용해야 합니다(다운스코핑만 허용됨).

    이 실행기는 어설션 파라미터를 사용하는 모든 요청에 사용할 수 있습니다. 현재 JWT 인가 그랜트의 assertion과 표준 토큰 교환(Standard Token Exchange)의 subject_token에 사용됩니다.

  • 실행기 jwt-claim-enforcer. 이 실행기는 JWT 어설션 토큰의 클레임에 대한 추가 요구 사항을 설정할 수 있게 해줍니다. 예를 들어, 어설션에 iat 클레임 또는 특정 값이 있는 커스텀 클레임이 포함되어야 하는 경우. 설정을 통해 클레임 이름과 클레임 값(Java 정규 표현식 사용)을 설정할 수 있습니다. JWT 어설션의 클레임이 정규 표현식과 일치하지 않으면, 요청이 진행되지 않고 오류가 반환됩니다.

    이전 실행기와 마찬가지로, 현재 이 실행기는 JWT 인가 그랜트와 표준 토큰 교환에 사용할 수 있습니다.

Google ID 제공자를 위한 JWT 인가 그랜트

Google ID 제공자(Google Identity Provider)는 JWT 인가 그랜트를 지원하며, Google ID 토큰(Google ID Token)을 어설션으로 사용할 수 있습니다. RFC 7523에 따르면, 어설션은 반드시 JWT여야 합니다. Google은 ID 토큰에 대해서만 JWT를 발급하며(액세스 토큰에는 발급하지 않음), 이 인가 그랜트에는 ID 토큰만 사용할 수 있습니다.

이 기능을 활성화하려면, Google ID 제공자 설정에서 JWT Authorization Grant 스위치를 켜야 합니다.

Google ID Token 페이로드 예시:

{
    "iss": "https://accounts.google.com", (1)
    "azp": "XXXX.apps.googleusercontent.com",
    "aud": "XXXX.apps.googleusercontent.com", (2)
    "sub": "100209199795938692365", (3)
    "at_hash": "AAos4eSIx4b5uQ8N-OAPYg",
    "iat": 1769503848,
    "exp": 1769507448 (4)
}
  1. Google Issuer.
  2. Google ID 제공자에 설정된 것과 동일한 클라이언트 ID.
  3. Keycloak 사용자와 연결되어야 하는 Subject.
  4. iat 이후 1시간 후 만료.

이 가이드에서 설명한 사양들은 Google에도 적용되지만, 다음과 같은 예외가 있습니다:

  • 대상 검증(Audience Validation): Google은 ID 토큰에 커스텀 대상을 추가하는 것을 허용하지 않습니다. 따라서 ID 토큰은 토큰 엔드포인트 URL 또는 Keycloak Issuer URL을 포함할 수 없습니다. aud(audience) 클레임은 Google ID 제공자에 설정된 클라이언트 ID와 단순히 일치해야 합니다. 이것이 RFC 7523에서 유일한 편차입니다.

  • 재사용 확인(Replay Check): Google ID 토큰에는 jti 클레임이 없기 때문에 재사용 확인을 수행하는 것이 불가능합니다. 결과적으로 동일한 Google ID 토큰을 여러 번 사용할 수 있습니다.

  • Google ID 토큰 만료: Google ID 토큰의 유효 기간은 1시간으로 고정되어 있으며 수정할 수 없습니다. 유효 창을 제한하기 위해, 설정의 전용 속성을 통해 토큰의 최대 시간 제한을 설정할 수 있습니다. 기본값은 1시간(Google ID 토큰 수명과 일치)입니다.

Keycloak 없이 Google 로그인을 지원하는 모바일 애플리케이션이 이미 있는 시나리오에서, 나중에 Keycloak을 통합할 때 문제가 발생할 수 있습니다. 예를 들어, Keycloak이 모바일 앱에서 사용하는 것과 다른 Google 클라이언트를 사용하는 Google ID 제공자로 설정된 경우가 있을 수 있습니다.

이 경우, ID 토큰의 aud 클레임이 Google ID 제공자에 설정된 클라이언트 ID와 일치하지 않기 때문에 Google ID 토큰을 JWT 인가 그랜트에 사용할 수 없습니다.

이 문제를 해결하기 위해, 클라이언트 설정 섹션에서 언급된 Custom audience mapping 설정 옵션을 사용할 수 있습니다. 예를 들어, ID 제공자 별칭이 google인 경우, 다음 매핑을 통해 이전 대상을 유효한 것으로 설정할 수 있습니다.

google 제공자를 위한 커스텀 대상 매핑 Figure 3. google 제공자를 위한 커스텀 대상 매핑