OAuth DPoP 검수, 보호 API에서 확인할 7가지
AI 에이전트가 OAuth로 보호 API를 호출할 때 DPoP 액세스 토큰과 요청 증명을 검수하는 기준입니다. 토큰 해시, 키 불일치, Bearer 전환과 증명 재사용을 가상 입력으로 비교합니다.
이 글을 쓴 알파카랩스카카오·네이버·쿠팡 출신, 재하청 0%, 대기업·공공기관 등 18개사+ 레퍼런스
DPoP 보호 API는 토큰과 요청 증명의 키를 대조합니다. 갱신에 DPoP를 써도 액세스 토큰은 Bearer일 수 있습니다. 2026년 11월 10일 기준입니다.
에이전트가 문서 API에서 사용자의 자료를 읽는다고 해 보겠습니다. OAuth 토큰을 갱신할 때 DPoP 증명을 받더라도, API에서 쓰는 액세스 토큰은 Bearer일 수 있습니다. 두 단계에 쓰이는 토큰과 증명 조건을 각각 인수표에 적으면 API 호출에 어떤 보호가 적용되는지 확인할 수 있습니다.
발급 단계와 보호 API는 무엇을 각각 확인하나요?#
OAuth의 DPoP는 클라이언트가 가진 개인 키로 요청별 증명 JWT에 서명하는 방식입니다. DPoP 액세스 토큰을 발급하는 권한 서버는 토큰을 증명의 공개 키에 연결합니다. 보호 API는 액세스 토큰과 함께 받은 증명의 서명, 토큰에 연결된 공개 키와 증명 키의 일치, 실제 토큰의 해시를 확인합니다. 호출에는 Authorization: DPoP 방식으로 액세스 토큰을 제시하고 DPoP 헤더로 증명을 보냅니다. HTTP 인증 스킴 이름은 대소문자를 구분하지 않습니다. RFC 9449 보호 API 요청
발급과 검수의 경계는 공급자 사례에서 드러납니다. Google은 2026년 10월 발표에서 Google OAuth 플랫폼의 DPoP 적용 범위를 리프레시 토큰으로 설명했습니다. 해당 플랫폼의 API에 제시하는 액세스 토큰은 Bearer 방식을 유지한다고 밝혔습니다. 그 발표를 기준으로 인수표에는 갱신 시 키 검증과 API 요청 시 액세스 토큰 보호를 두 항목으로 나눠 적습니다. Google OAuth 발표
같은 토큰으로 무엇을 바꿔 검수하나요?#
아래 표는 읽기용 문서 API에서 DPoP 액세스 토큰만 받기로 한 가상 예시입니다. 기본 토큰과 증명 한 쌍을 기준으로 조건을 바꿔 어디에서 거부되는지 확인합니다. 두 방식을 지원하는 실제 API에서도 DPoP에 묶인 액세스 토큰을 Bearer로 받으면 거부해야 합니다. RFC 9449 Bearer 호환 조건
| 가상 요청 | 예상 결과 | 판정 근거 |
|---|---|---|
| 인증 스킴 dpop, 토큰·키·증명·요청 일치 | pass-dpop-check | 이 예시의 DPoP 판정 통과 |
| 증명 없음 | reject-scheme-or-proof | 보호 API에 증명 필요 |
| 같은 주소, 다른 메서드 | reject-target | 실제 HTTP 메서드와 htm 불일치 |
| 다른 액세스 토큰의 해시 | reject-token-hash | 실제로 받은 토큰과 ath 불일치 |
| 다른 키의 유효한 서명 | reject-key | 토큰에 묶인 키와 증명 키 불일치 |
| 같은 DPoP 토큰을 Bearer로 제시 | reject-scheme-or-proof | 인증 방식 우회 거부 |
| 유효 시간 안에 이미 소비한 증명 | reject-replay | 이 예시의 증명 한 번 사용 정책 |
예시의 token.valid는 신뢰하는 발급자의 토큰 서명이나 인증된 토큰 조회 결과를 확인한 뒤 만료·대상 API·이 요청에 필요한 권한을 검사한 결과입니다. proof.verified는 단일 헤더, JWT 형식과 필수 값, 허용한 비대칭 알고리즘, 공개 JWK와 서명, 유효 시간 및 서버가 요구한 nonce를 검증한 결과입니다. 양쪽 키 지문은 검증된 입력에서 구합니다. 예시의 targetUri와 htu에는 검증 단계에서 RFC 비교 규칙을 적용한 값을 넘깁니다. 비교에서 쿼리와 프래그먼트는 제외합니다. RFC 9449 증명 검사
import { createHash } from "node:crypto";
export function checkSample(req, token, proof, consumeProof) {
if (req.scheme?.toLowerCase() !== "dpop" || !proof) return "reject-scheme-or-proof";
if (!token.valid || !proof.verified) return "reject-validation";
if (proof.htm !== req.method || proof.htu !== req.targetUri) {
return "reject-target";
}
const ath = createHash("sha256").update(token.value, "ascii")
.digest("base64url");
if (proof.ath !== ath) return "reject-token-hash";
if (!token.keyThumbprint || proof.keyThumbprint !== token.keyThumbprint) {
return "reject-key";
}
if (!consumeProof()) return "reject-replay";
return "pass-dpop-check";
}실제 인수표에는 증명 누락, 서명 위조, 주소 변경, 시간 초과, nonce 불일치, 다른 토큰과 키를 각각 적고 보호 API의 응답과 업무 동작 여부를 함께 대조합니다. 프록시가 주소를 바꾸는 환경에서는 신뢰할 수 있는 경로에서 실제 대상 URI를 재구성했는지 확인합니다. 권한 서버, 게이트웨이 또는 증명 처리 라이브러리가 바뀌면 같은 표본을 다시 검수합니다.
증명 재사용과 업무 재시도는 어떻게 나누나요?#
같은 HTTP 요청에서 캡처한 증명이 재사용될 수 있으므로 RFC 9449는 증명의 수용 시간을 짧게 제한하도록 요구합니다. 증명에는 고유 ID인 jti가 필수입니다. 서버가 같은 대상 URI에서 받은 ID를 저장해 다시 나타나면 거부하는 것은 RFC가 설명하는 추가 방어입니다. 예시의 consumeProof는 앞의 조건을 통과한 뒤 증명 ID를 원자적으로 확인하고 처음이면 소비하는 함수를 가정합니다. 검수에서는 유효 범위에 남은 ID를 다시 받으면 거부하는지 확인합니다. 여러 인스턴스가 같은 요청을 받으면 이 정책이 인스턴스 사이에서도 유지되는지 시험합니다. 이 함수에는 저장소 동작이 들어 있지 않습니다. RFC 9449 증명 재생
다른 증명을 붙여 같은 업무 요청을 다시 보낼 수도 있습니다. 중복 결재나 중복 등록은 업무 요청의 멱등성으로 다룹니다. DPoP 증명은 요청의 메서드와 URI를 확인하지만 본문과 쿼리 전체를 보호하지 않으므로 TLS와 별도의 권한 검사가 필요합니다. 액세스 토큰의 DPoP 보호가 보안 요구인 연동에서 발급 응답의 token_type이 DPoP가 아니면 클라이언트는 그 응답을 폐기해야 합니다. 이 경우 인수를 보류합니다. Bearer를 허용한 연동은 지원 범위를 인수표에 표시하고 토큰 권한과 수명을 별도로 검수합니다. RFC 9449 발급 응답 도구별 권한·승인의 범위는 기업용 MCP 서버 구축 가이드에서 다룹니다.
어떤 문서에서 기준을 확인했나요?#
- IETF RFC 9449는 요청별 증명과 키·토큰·메서드·URI의 검증을 정의합니다. 2023년 9월 공개.
- IETF RFC 9700 §2.2는 탈취한 토큰의 사용을 줄이기 위해 액세스 토큰 발신자 제한을 권고하고, 공개 클라이언트의 리프레시 토큰은 발신자 제한 또는 회전을 요구합니다. 2025년 1월 공개.
- Google OAuth DPoP 공식 발표는 해당 플랫폼의 리프레시 토큰 적용과 액세스 토큰 Bearer 유지를 구분합니다. 2026년 10월 15일 공개.
- 알파카랩스 업무 자동화·API 연동은 API 접근 조건, 실패·중복 처리와 운영 인수 범위를 협의하는 서비스를 안내합니다.
- IETF RFC 9110 §11.1은 HTTP 인증 스킴 이름이 대소문자를 구분하지 않는다고 정의합니다. 2022년 6월 공개.
원문은 2026년 11월 10일 확인했습니다. 표의 거부 라벨과 증명 한 번 사용 정책은 가상 설계의 판정입니다.
자주 묻는 질문#
토큰 갱신 때 DPoP를 쓰면 실제 API 요청도 DPoP인가요?
보호 범위를 따로 확인해야 합니다. 리프레시 토큰만 키에 묶이고 API에 사용하는 액세스 토큰은 Bearer인 공급자 흐름도 있습니다.
증명 JWT의 서명이 유효하면 요청을 통과시켜도 되나요?
액세스 토큰에 묶인 키, 실제 토큰의 해시, 요청 메서드와 URI, 유효 시간과 필요한 nonce, 토큰의 기본 유효성과 권한도 확인합니다.
ath와 htu는 각각 무엇을 확인하나요?
ath는 요청에서 실제로 제시한 액세스 토큰의 해시입니다. htu는 쿼리와 프래그먼트를 뺀 요청 대상 URI를 비교하는 데 씁니다.
DPoP 액세스 토큰을 Bearer로 보내도 되나요?
두 인증 방식을 모두 지원하는 보호 API는 DPoP에 묶인 액세스 토큰을 Bearer 방식으로 제시하면 거부해야 합니다.
증명 ID 중복 검사가 업무 중복도 막나요?
증명 ID 검사는 같은 증명의 재사용을 제한합니다. 새 증명으로 같은 업무를 다시 요청할 수 있으므로 업무 중복은 별도의 멱등성 기준으로 검수합니다.
API 연동 인수표를 정할 때#
보호 API의 DPoP 검수 범위를 정리합니다
첫 범위 협의에서 비식별한 인증 흐름과 통과·거부 표본으로 보호 API의 검수 범위를 정리합니다. 소요 시간은 테스트 범위와 권한 서버의 지원 조건을 확인한 뒤 협의합니다.
DPoP 연동 인수표 초안 협의