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되었는지는 자체 검증만으로는 알 수 없습니다. 아래 중 하나:
- 옵트인 — 민감 엔드포인트만
/oauth/userinfo호출해 logi에서 재검증 (15분 만료 기준으로 대부분 충분) - Webhook —
token.revoked이벤트 구독 (logi → 제휴사).jwt_jti수신 시 로컬 블랙리스트에 추가 - 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와 동일하되 nonce와 at_hash를 비교하세요 (replay + token 바인딩 방어).