Skip to content

JWKS & JWT 검증

logi는 Access Token으로 RS256 JWT를 발급합니다. 제휴사는 stateless로 서명을 검증하거나, revocation을 확인하려면 /oauth/userinfo 를 호출합니다.

JWKS 엔드포인트

GET /.well-known/jwks.json

응답 예시:

json
{
  "keys": [
    {
      "kty": "RSA",
      "use": "sig",
      "alg": "RS256",
      "kid": "ffaa476406e8abec",
      "n": "xqJbzP...",
      "e": "AQAB"
    }
  ]
}

Cache-Control: public, max-age=3600 헤더가 붙어있어 1시간 캐시 가능합니다.

키 Rotation

  • 분기 1회 새 키를 발급 + kid 변경
  • 구 키는 JWKS에 90일 grace period 동안 유지 (기존 발급 토큰 검증용)
  • 신규 발급은 활성 kid로만 서명

제휴사 구현 시 JWKS 캐시를 1시간 ~ 1일 기준으로 refresh. 검증 실패 시 한 번 강제 refresh 후 재시도.

Payload 스키마

json
{
  "iss": "logi",
  "sub": "42",
  "aud": "logi_a1b2c3d4...",
  "exp": 1734567890,
  "iat": 1734566990,
  "jti": "9d6f...-...-...",
  "scope": "profile email"
}

언어별 검증 예시

ts
import { jwtVerify, createRemoteJWKSet } from "jose";

const jwks = createRemoteJWKSet(new URL("https://logi.example.com/.well-known/jwks.json"));

const { payload } = await jwtVerify(accessToken, jwks, {
  issuer: "logi",
  audience: "logi_a1b2c3d4...",  // 내 앱 client_id
});
console.log(payload.sub);
ruby
require "jwt"
require "open-uri"

jwks_raw = URI.open("https://logi.example.com/.well-known/jwks.json").read
jwks = JWT::JWK::Set.new(JSON.parse(jwks_raw))

payload, _header = JWT.decode(
  access_token, nil, true,
  algorithms: ["RS256"],
  iss: "logi", verify_iss: true,
  aud: ENV["LOGI_CLIENT_ID"], verify_aud: true,
  jwks: jwks
)
python
import jwt
import requests

jwks = jwt.PyJWKClient("https://logi.example.com/.well-known/jwks.json")
signing_key = jwks.get_signing_key_from_jwt(access_token)
payload = jwt.decode(
    access_token, signing_key.key,
    algorithms=["RS256"],
    issuer="logi",
    audience="logi_a1b2c3d4...",
)
go
import "github.com/lestrrat-go/jwx/v2/jwk"

jwks, _ := jwk.Fetch(ctx, "https://logi.example.com/.well-known/jwks.json")
tok, err := jwt.Parse([]byte(accessToken),
    jwt.WithKeySet(jwks),
    jwt.WithIssuer("logi"),
    jwt.WithAudience("logi_a1b2c3d4..."),
)

만료 이후

  • exp 지나면 expired_token 에러
  • Refresh Token으로 /oauth/token 재호출하여 새 AT 발급

Revoke 즉시 확인이 필요하면

JWT는 stateless라 jti가 revoke되었는지는 자체 검증만으로는 알 수 없습니다. 아래 중 하나:

  1. 옵트인 — 민감 엔드포인트만 /oauth/userinfo 호출해 logi에서 재검증 (15분 만료 기준으로 대부분 충분)
  2. Webhooktoken.revoked 이벤트 구독 (logi → 제휴사). jwt_jti 수신 시 로컬 블랙리스트에 추가
  3. Introspection/oauth/introspect 호출로 active 상태를 직접 확인

id_token (OIDC)

openid scope 요청 시 /oauth/token 응답에 id_token이 포함됩니다. 포함 claim:

  • iss, sub, aud, exp, iat, nonce (요청 시)
  • at_hash — left 128bits of SHA256(access_token), base64url (RFC 7519 §3.1.3.6)

검증 방법은 AT와 동일하되 nonceat_hash를 비교하세요 (replay + token 바인딩 방어).

MIT License · Identity가 제품의 신뢰를 만듭니다.