Authentication
key가 호출할 수 있는 서비스와 API의 범위를 정의합니다.
managed key는 기본적으로 전체 scope를 가집니다. 카탈로그의 모든 서비스를 읽고 쓸 수 있다는 뜻입니다. scope는 key별로 그 범위를 좁혀서, 유출되거나 잘못 쓰인 key가 허용된 것 이상을 하지 못하게 합니다.
scope는 <providerId>:read 또는 <providerId>:write 형식입니다. <providerId> 자리에는 서비스 id가 들어가며, API 레퍼런스 경로의 첫 세그먼트와 같습니다. 예: catch-table, baemin. scope는 key를 발급할 때 지정하며 하나의 key에 여러 개를 조합할 수 있습니다. 읽기와 쓰기 구분은 HTTP 메서드를 따릅니다. GET은 read, POST와 DELETE 같은 변경 호출은 write입니다.
<providerId>:read는 해당 서비스의 읽기 API를 허용합니다.<providerId>:write는 쓰기 API를 허용하며, 같은 서비스의 read를 함께 포함합니다. write만 부여해도 조회가 가능합니다.*:read는 유일한 wildcard입니다. 현재와 이후에 추가될 모든 서비스의 읽기를 허용하지만, 어떤 쓰기도 허용하지 않습니다. 쓰기 wildcard는 없습니다.| scope 조합 | 허용 | 거부 |
|---|---|---|
catch-table:read | Search restaurants, Get availability 같은 Catch Table 읽기 | Catch Table 쓰기와 다른 모든 서비스 |
catch-table:write | Create reservation을 포함한 Catch Table 전체. write가 read를 포함합니다. | 다른 모든 서비스 |
*:read | 모든 서비스의 읽기 | 모든 쓰기 |
*:read, catch-table:write | 모든 서비스의 읽기와 Catch Table 쓰기 | 다른 서비스의 쓰기 |
| (지정 없음) | 전체 scope. 모든 서비스의 읽기와 쓰기 | 없음 |
key가 scope 밖의 호출을 하면 게이트웨이가 서비스에 아무것도 전달하기 전에 403으로 응답합니다. 에러 envelope의 code는 scope_denied이고 retryable은 false입니다. 같은 key로 같은 요청을 재시도해도 결과는 바뀌지 않습니다. 응답에 provider 필드가 없는 것은 이 에러가 서비스가 아니라 게이트웨이에서 발생하기 때문입니다.
# 이 key의 scope는 catch-table:read뿐입니다.
curl -X POST "https://api.frism.dev/v1/catch-table/reservations" \
-H "Authorization: Bearer frism_test_k3xample" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: idem_b1f7c2d0" \
-d '{
"restaurant_id": "res_01J8Q9W3TE",
"slot_id": "slt_1900_2",
"party_size": 2,
"contact_name": "Han Jiwoo"
}'{
"error": {
"code": "scope_denied",
"message": "This key does not carry catch-table:write.",
"request_id": "req_01J8QGX2M4",
"retryable": false
}
}scope_denied는 런타임 상황이 아니라 설정 버그로 취급합니다. request_id를 로그에 남기고, key의 scope 또는 코드 경로를 고칩니다. 분기는 항상 error.code로 하고 message는 파싱하지 않습니다.
const response = await fetch(
"https://api.frism.dev/v1/catch-table/reservations",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.FRISM_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "idem_b1f7c2d0",
},
body: JSON.stringify({
restaurant_id: "res_01J8Q9W3TE",
slot_id: "slt_1900_2",
party_size: 2,
contact_name: "Han Jiwoo",
}),
},
);
if (!response.ok) {
const { error } = await response.json();
if (error.code === "scope_denied") {
// 설정 문제입니다. 재시도하는 대신 key의 scope를 확인합니다.
throw new Error(`Missing scope for catch-table (${error.request_id})`);
}
throw new Error(`${error.code}: ${error.message}`);
}
const reservation = await response.json();sandbox에서는 전체 scope의 key로 자유롭게 실험해도 됩니다. 반면 live key는 유출되었을 때의 피해 범위가 곧 부여한 scope의 범위입니다. live 전환 전에 다음을 적용합니다.
*:read, 예약 백엔드에는 catch-table:write가 어울립니다.read만 부여합니다. 나중에 write를 추가하는 것은 대시보드 설정과 일 뿐, 코드 변경이 아닙니다.scope에 쓰는 서비스 id는 각 서비스의 API 레퍼런스(예: )에서 확인합니다. 403을 포함한 모든 상태 코드 매핑은 에 있습니다.