PKCE를 사용한 인증 코드 플로우
PKCE를 사용한 인증 코드 플로우는 모바일 앱, 단일 페이지 웹 앱 또는 클라이언트 시크릿을 안전하게 저장할 수 없는 다른 유형의 애플리케이션에서 권장되는 인증 플로우입니다.
PKCE 확장의 구현은 다음 단계로 구성됩니다:
- 코드 검증기를 사용하여 코드 챌린지를 생성합니다.
- 사용자로부터 권한을 요청하고 인증 코드를 가져옵니다.
- 인증 코드를 사용하여 액세스 토큰을 요청합니다.
- 마지막으로, 액세스 토큰을 사용하여 API 호출을 수행합니다.
전제 조건
이 가이드는 다음을 전제로 합니다:
- 인증 가이드를 읽었습니다.
- 앱 가이드를 따라 앱을 생성했습니다.
예시
GitHub의 web-api-examples 저장소에서 PKCE 확장이 포함된 인증 코드 플로우를 구현한 예제 앱을 찾을 수 있습니다.
코드 검증기
PKCE 인증 플로우는 코드 검증기를 생성하는 것으로 시작됩니다. PKCE 표준에 따르면, 코드 검증기는 43자에서 128자 사이의 길이를 가진 고난도 암호화 무작위 문자열입니다(길수록 좋습니다). 이 문자열은 문자, 숫자, 밑줄, 마침표, 하이픈 또는 물결표를 포함할 수 있습니다.
코드 검증기는 다음 JavaScript 함수를 사용하여 구현할 수 있습니다:
코드 예시: JavaScript
const generateRandomString = (length) => {
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const values = crypto.getRandomValues(new Uint8Array(length));
return values.reduce((acc, x) => acc + possible[x % possible.length], "");
}
const codeVerifier = generateRandomString(64);
코드 챌린지
코드 검증기가 생성된 후, 이를 SHA256 알고리즘을 사용하여 변환(해시)해야 합니다. 이 값이 사용자 권한 요청 시 전송될 값입니다.
window.crypto.subtle.digest
를 사용하여 제공된 데이터를 통해 SHA256 알고리즘을 사용하여 값을 생성합시다:
코드 예시: JavaScript
const sha256 = async (plain) => {
const encoder = new TextEncoder()
const data = encoder.encode(plain)
return window.crypto.subtle.digest('SHA-256', data)
}
다음으로, base64encode
라는 함수를 구현하여 sha256
함수로 계산된 다이제스트의 base64 표현을 반환합니다:
코드 예시: JavaScript
const base64encode = (input) => {
return btoa(String.fromCharCode(...new Uint8Array(input)))
.replace(/=/g, '')
.replace(/\+/g, '-')
.replace(/\//g, '_');
}
이제 모든 조각을 결합하여 코드 챌린지 생성을 구현합니다:
코드 예시: JavaScript
const hashed = await sha256(codeVerifier)
const codeChallenge = base64encode(hashed);
사용자 권한 요청
사용자에게 권한을 요청하기 위해, /authorize
엔드포인트에 GET 요청을 보내야 합니다. 이 요청에는 인증 코드 플로우와 동일한 매개변수 외에 두 개의 추가 매개변수 code_challenge
와 code_challenge_method
가 포함되어야 합니다:
쿼리 매개변수 | 필수 여부 | 값 |
---|---|---|
client_id | 필수 | 애플리케이션 등록 후 생성된 클라이언트 ID |
response_type | 필수 | code 로 설정 |
redirect_uri | 필수 | 사용자가 권한을 부여하거나 거부한 후 리디렉션할 URI. 이 URI는 애플리케이션을 등록할 때 지정한 리디렉션 URI 허용 목록에 입력되어 있어야 합니다. 여기서 redirect_uri 의 값은 애플리케이션을 등록할 때 입력한 값과 정확히 일치해야 합니다. 대소문자, 슬래시 포함 여부 등을 포함하여 정확히 일치해야 합니다. |
state | 선택 사항 | 크로스 사이트 요청 위조와 같은 공격으로부터 보호하기 위해 이 매개변수를 사용하는 것이 강력히 권장됩니다. RFC-6749를 참조하세요. |
scope | 선택 사항 | 공백으로 구분된 스코프 목록. 스코프가 지정되지 않은 경우, 공개적으로 이용 가능한 정보에만 접근할 수 있는 권한이 부여됩니다. 즉, Spotify 데스크톱, 웹 및 모바일 플레이어에서 일반적으로 볼 수 있는 정보만 접근할 수 있습니다. |
code_challenge_method | 필수 | S256 으로 설정 |
code_challenge | 필수 | 이전 단계에서 애플리케이션이 계산한 코드 챌린지로 설정 |
사용자 권한 요청을 위한 코드는 다음과 같습니다:
코드 예시: JavaScript
const clientId = 'YOUR_CLIENT_ID';
const redirectUri = 'http://localhost:8080';
const scope = 'user-read-private user-read-email';
const authUrl = new URL("https://accounts.spotify.com/authorize")
// 이전 단계에서 생성됨
window.localStorage.setItem('code_verifier', codeVerifier);
const params = {
response_type: 'code',
client_id: clientId,
scope,
code_challenge_method: 'S256',
code_challenge: codeChallenge,
redirect_uri: redirectUri,
}
authUrl.search = new URLSearchParams(params).toString();
window.location.href = authUrl.toString();
애플리케이션은 PKCE 코드 챌린지를 생성하고 window.location
객체의 값을 업데이트하여 Spotify 인증 서버 로그인 페이지로 리디렉션합니다. 이를 통해 사용자는 애플리케이션에 대한 권한을 부여할 수 있습니다.
코드 검증기 값은 localStorage
JavaScript 속성을 사용하여 로컬에 저장되며, 다음 인증 플로우 단계에서 사용됩니다.
응답
사용자가 요청한 권한을 수락하면, OAuth 서비스는 사용자를 redirect_uri
필드에 지정된 URL로 다시 리디렉션합니다. 이 콜백에는 URL에 두 개의 쿼리 매개변수가 포함됩니다:
쿼리 매개변수 | 값 |
---|---|
code | 액세스 토큰으로 교환할 수 있는 인증 코드 |
state | 요청 시 제공한 state 매개변수의 값 |
그런 다음, URL을 파싱하여 code
매개변수를 가져와야 합니다:
코드 예시: JavaScript
const urlParams = new URLSearchParams(window.location.search);
let code = urlParams.get('code');
이 코드는 다음 단계에서 액세스 토큰을 요청하는 데 필요합니다.
사용자가 요청을 수락하지 않거나 오류가 발생한 경우, 응답 쿼리 문자열에는 다음 매개변수가 포함됩니다:
쿼리 매개변수 | 값 |
---|---|
error | 인증 실패 이유, 예: "access_denied" |
state | 요청 시 제공한 state 매개변수의 값 |
액세스 토큰 요청
이전 단계에서 사용자가 인증 요청을 수락한 후, 인증 코드를 액세스 토큰으로 교환할 수 있습니다. /api/token
엔드포인트에 다음 매개변수를 포함하여 POST 요청을 보내야 합니다:
본문 매개변수 | 필수 여부 | 값 |
---|---|---|
grant_type | 필수 | authorization_code 값을 포함해야 합니다. |
code | 필수 | 이전 요청에서 반환된 인증 코드 |
redirect_uri | 필수 | 이 매개변수는 검증에만 사용됩니다(실제로 리디렉션되지 않음). 이 매개변수의 값은 인증 코드를 요청할 때 제공한 redirect_uri 값과 정확히 일치해야 합니다. |
client_id | 필수 | 개발자 대시보드에서 제공되는 애플리케이션의 클라이언트 ID |
code_verifier | 필수 | 이전 단계에서 생성한 코드 검증기의 값 |
요청에는 다음 HTTP 헤더가 포함되어야 합니다:
헤더 매개변수 | 필수 여부 | 값 |
---|---|---|
Content-Type | 필수 | application/x-www-form-urlencoded 로 설정 |
토큰 요청은 다음 JavaScript 함수로 구현할 수 있습니다:
코드 예시: JavaScript
const getToken = async code => {
// 이전 단계에서 저장됨
let codeVerifier = localStorage.getItem('code_verifier');
const payload = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
client_id: clientId,
grant_type: 'authorization_code',
code,
redirect_uri: redirectUri,
code_verifier: codeVerifier,
}),
}
const body = await fetch(url, payload);
const response = await body.json();
localStorage.setItem('access_token', response.access_token);
}
응답
성공 시, 응답은 200 OK
상태를 가지며 응답 본문에 다음 JSON 데이터를 포함합니다:
키 | 타입 | 설명 |
---|---|---|
access_token | string | 이후의 호출에서 예: Spotify 웹 API 서비스에 제공할 수 있는 액세스 토큰 |
token_type | string | 액세스 토큰을 사용할 수 있는 방식: 항상 "Bearer" |
scope | string | 이 access_token 에 대해 부여된 스코프를 공백으로 구분한 목록 |
expires_in | int | 액세스 토큰이 유효한 기간(초) |
refresh_token | string | 토큰 새로 고침을 참조하세요. |
다음 단계는?
축하합니다! 액세스 토큰을 발급받았습니다. 이제 이 토큰을 어떻게 사용할 수 있는지 궁금하실 것입니다. 새로 발급된 액세스 토큰을 사용하여 API 호출을 수행하는 방법은 액세스 토큰 가이드를 참조하세요.
액세스 토큰이 만료된 경우, 사용자가 애플리케이션을 다시 인증하지 않고도 새 토큰을 발급받는 방법을 배우려면 토큰 새로 고침 가이드를 읽어보세요.
'Coding History > project' 카테고리의 다른 글
스포티파이 for Developers 튜토리얼 번역 ( 4 ) (0) | 2024.08.29 |
---|---|
스포티파이 for Developers 튜토리얼 번역 ( 3 ) (0) | 2024.08.29 |
스포티파이 for Developers 튜토리얼 번역 ( 1 ) (1) | 2024.08.29 |
개인 프로젝트 DB 설계중. (0) | 2024.08.27 |
계획단계(판매권한 심사 시스템) (0) | 2024.08.26 |