OAuth 2.0 인증

Checkable 서비스는 OAuth 2.0 프로토콜을 사용하여 사용자 인증을 제공합니다. 이 문서에서는 Checkable 서비스의 OAuth 2.0 구현 방법과 API 사용법을 설명합니다.

개요

OAuth 2.0을 사용하면 사용자가 사용자 이름, 비밀번호, 기타 정보를 비공개로 유지하면서 특정 데이터를 애플리케이션과 공유할 수 있습니다. 예를 들어 애플리케이션은 OAuth 2.0을 사용하여 사용자로부터 Checkable 서비스의 데이터에 대한 액세스 권한을 얻을 수 있습니다.

서비스 정보

  • 도메인: https://checkable.app
  • 인증 방식: OAuth 2.0 with PKCE (Public Clients) / OAuth 2.0 with Client Secret (Confidential Clients)
  • 지원 플랫폼: Android, iOS, Web
  • 보안: PKCE를 통한 인증 코드 인터셉션 공격 방지

기본 요건

1. OAuth 클라이언트 발급

Checkable 서비스에서 OAuth 2.0을 사용하려면 먼저 OAuth 클라이언트를 발급받아야 합니다. 클라이언트 발급은 Checkable 개발팀에 요청하여 진행됩니다. 클라이언트 타입:
  • Public Client: 모바일 앱, SPA 등 (client_secret 없음)
  • Confidential Client: 서버 애플리케이션 (client_secret 필요)
발급 정보:
  • client_id: 고유한 클라이언트 식별자
  • client_secret: Confidential Client만 (Public Client는 사용하지 않음)
  • redirect_uris: 허용된 리디렉션 URI 목록
  • scopes: 요청할 권한 범위
  • client_type: public 또는 confidential

2. 지원되는 범위

현재 Checkable 서비스에서는 다음 범위를 지원합니다:
  • all: 모든 권한 (기본값)

OAuth 2.0 액세스 토큰 가져오기

1단계: 코드 검증기 및 챌린지 생성 (PKCE)

Checkable 서비스는 설치된 앱 흐름을 더 안전하게 만들기 위해 코드 교환용 증명 키(PKCE) 프로토콜을 지원합니다. Public Client의 경우 모든 승인 요청에 대해 고유한 코드 검증기가 생성되고 code_challenge라는 변환된 값이 승인 서버로 전송되어 승인 코드를 가져옵니다.

코드 검증기 만들기

code_verifier는 예약되지 않은 문자 [A-Z] / [a-z] / [0-9] / '-' / '.' / '_' / '~'을 사용하는 엔트로피가 높은 암호화 랜덤 문자열로, 최소 길이는 43자, 최대 길이는 128자입니다.
// 코드 검증기 생성 예시
function generateCodeVerifier() {
  const array = new Uint8Array(32);
  crypto.getRandomValues(array);
  return base64URLEncode(array);
}

코드 챌린지 만들기

코드 챌린지를 만드는 방법이 지원됩니다:
  • S256 (권장): 코드 챌린지는 코드 검증기의 SHA256 해시를 Base64URL로 인코딩한 것입니다 (패딩 없음)
// 코드 챌린지 생성 예시
function generateCodeChallenge(codeVerifier) {
  const hash = crypto.createHash('sha256');
  hash.update(codeVerifier);
  return base64URLEncode(hash.digest());
}

2단계: Checkable OAuth 2.0 서버에 요청 전송

사용자 승인을 얻으려면 https://checkable.app/api/oauth/authorize의 Checkable 승인 서버에 요청을 전송합니다.

승인 서버 매개변수

매개변수필수설명
client_id필수애플리케이션의 클라이언트 ID
redirect_uri필수승인 서버가 앱에 응답을 전송하는 방법을 결정
response_type필수code로 설정
scope필수공백으로 구분된 범위 목록 (예: all)
code_challenge권장PKCE 코드 챌린지
code_challenge_method권장S256 또는 plain
state권장CSRF 방지를 위한 임의의 문자열

샘플 승인 URL

https://checkable.app/api/oauth/authorize?
 scope=all&
 response_type=code&
 state=YOUR_STATE_VALUE&
 redirect_uri=YOUR_REDIRECT_URI&
 client_id=YOUR_CLIENT_ID&
 code_challenge=YOUR_CODE_CHALLENGE&
 code_challenge_method=S256
매개변수 설명:
  • YOUR_CLIENT_ID: 발급받은 클라이언트 ID
  • YOUR_REDIRECT_URI: 등록된 리디렉션 URI
  • YOUR_STATE_VALUE: CSRF 방지를 위한 임의의 문자열
  • YOUR_CODE_CHALLENGE: PKCE 코드 챌린지 (S256 방식)

3단계: 사용자 동의 화면

이 단계에서 사용자는 애플리케이션에 요청된 액세스 권한을 부여할지 결정합니다. Checkable 서비스는 애플리케이션의 이름과 사용자의 승인 사용자 인증 정보에 대한 액세스 권한을 요청하는 서비스, 부여할 액세스 범위의 요약을 보여주는 동의 창을 표시합니다.

4단계: OAuth 2.0 서버 응답 처리

애플리케이션이 승인 응답을 수신하는 방식은 애플리케이션에서 사용하는 리디렉션 URI 스킴에 따라 다릅니다. 성공 응답:
YOUR_REDIRECT_URI?code=AUTHORIZATION_CODE&state=YOUR_STATE_VALUE
오류 응답:
YOUR_REDIRECT_URI?error=access_denied&state=YOUR_STATE_VALUE

5단계: 승인 코드를 액세스 토큰으로 교환

승인 코드를 액세스 토큰으로 교환하려면 https://checkable.app/api/auth/member/oauth2/token 엔드포인트를 호출합니다.

Public Client (PKCE 방식)

Public Client는 보안을 위해 PKCE 방식을 필수로 사용합니다. client_secret이 필요하지 않습니다.
POST /api/auth/member/oauth2/token HTTP/1.1
Host: checkable.app
Content-Type: application/x-www-form-urlencoded

code=AUTHORIZATION_CODE&
client_id=YOUR_CLIENT_ID&
redirect_uri=YOUR_REDIRECT_URI&
grant_type=authorization_code&
code_verifier=YOUR_CODE_VERIFIER

Confidential Client (일반 방식)

Confidential Client는 client_secret을 사용하여 인증합니다.
POST /api/auth/member/oauth2/token HTTP/1.1
Host: checkable.app
Content-Type: application/x-www-form-urlencoded

code=AUTHORIZATION_CODE&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET&
redirect_uri=YOUR_REDIRECT_URI&
grant_type=authorization_code

Confidential Client (Basic Auth 방식)

Confidential Client는 Basic Auth 헤더를 사용할 수도 있습니다.
POST /api/auth/member/oauth2/token HTTP/1.1
Host: checkable.app
Authorization: Basic base64(YOUR_CLIENT_ID:YOUR_CLIENT_SECRET)
Content-Type: application/x-www-form-urlencoded

code=AUTHORIZATION_CODE&
redirect_uri=YOUR_REDIRECT_URI&
grant_type=authorization_code

토큰 응답

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token_expires_in": 2592000,
  "scope": "all"
}

액세스 토큰 갱신

액세스 토큰은 주기적으로 만료되어 관련 API 요청에 대한 잘못된 사용자 인증 정보가 됩니다. 액세스 토큰을 새로고침하기 위해 애플리케이션은 다음 매개변수가 포함된 HTTPS POST 요청을 Checkable의 승인 서버로 전송합니다.
POST /api/auth/member/oauth2/token HTTP/1.1
Host: checkable.app
Content-Type: application/x-www-form-urlencoded

client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET&
refresh_token=YOUR_REFRESH_TOKEN&
grant_type=refresh_token
참고: Public Client의 경우 client_secret 없이도 토큰 갱신이 가능할 수 있습니다. 클라이언트 타입에 따라 서버에서 자동으로 처리됩니다.

사용자 정보 조회

액세스 토큰을 사용하여 사용자 정보를 조회할 수 있습니다.
GET /api/auth/member/oauth2/me HTTP/1.1
Host: checkable.app
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
성공 응답:
{
  "member": {
    "id": 123,
    "name": "discord_username",
    "email": "user@example.com"
  }
}
오류 응답:
{
  "error": "UNAUTHORIZED",
  "message": "Member not found"
}
참고: Discord SSO가 연결되지 않은 사용자의 경우 Member not found 오류가 발생할 수 있습니다.

API 호출

애플리케이션이 액세스 토큰을 획득한 후 이 토큰을 사용하여 특정 사용자 계정을 대신하여 Checkable API를 호출할 수 있습니다.

HTTP 헤더 사용

GET /api/syt/challenges HTTP/1.1
Host: checkable.app
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

curl 예시

curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
     -H "Content-Type: application/json" \
     https://checkable.app/api/syt/challenges

오류 처리

일반적인 HTTP 상태 코드

  • 200 OK: 요청 성공
  • 400 Bad Request: 잘못된 요청 (필수 매개변수 누락 등)
  • 401 Unauthorized: 인증 실패 (토큰 만료, 잘못된 토큰 등)
  • 403 Forbidden: 권한 없음
  • 404 Not Found: 리소스를 찾을 수 없음
  • 500 Internal Server Error: 서버 오류

OAuth 2.0 오류 응답

{
  "error": "invalid_request",
  "error_description": "The authorization code is invalid or has expired."
}

주요 오류 메시지

오류 메시지설명해결 방법
The authorization code is invalid or has expired.인증 코드가 잘못되었거나 만료됨새로운 인증 코드 요청
The redirect URI does not match the registered URI.리디렉션 URI가 등록된 URI와 일치하지 않음올바른 redirect_uri 사용
The PKCE code verifier is invalid. Please check your code_verifier parameter.PKCE 코드 검증기가 잘못됨올바른 code_verifier 사용
The client ID is invalid.클라이언트 ID가 잘못됨올바른 client_id 사용
The client secret is invalid.클라이언트 시크릿이 잘못됨올바른 client_secret 사용
The refresh token is invalid or has expired.갱신 토큰이 잘못되었거나 만료됨새로운 인증 코드 요청
Refresh token is required.갱신 토큰이 필요함refresh_token 매개변수 포함
Unsupported grant type.지원하지 않는 grant_type올바른 grant_type 사용
Unsupported client type.지원하지 않는 클라이언트 타입클라이언트 타입 확인

보안 고려사항

1. PKCE 필수 사용 (Public Client)

Checkable 서비스는 보안을 위해 Public Client에서 PKCE를 필수로 사용합니다. 모든 OAuth 2.0 요청에서 코드 검증기와 코드 챌린지를 포함해야 합니다.

2. 토큰 저장

  • 액세스 토큰과 갱신 토큰을 안전하게 저장하세요
  • iOS: Keychain 사용 권장
  • Android: EncryptedSharedPreferences 사용 권장
  • Web: HttpOnly 쿠키 또는 안전한 로컬 스토리지 사용

3. 토큰 갱신

  • 액세스 토큰이 만료되기 전에 갱신 토큰을 사용하여 새 토큰을 요청하세요
  • 갱신 토큰도 만료될 수 있으므로 적절한 오류 처리를 구현하세요

4. CSRF 방지

  • state 매개변수를 사용하여 CSRF 공격을 방지하세요
  • 임의의 문자열을 생성하고 응답에서 동일한 값인지 확인하세요

클라이언트 설정

각 클라이언트는 고유한 리디렉션 URI를 사용합니다. 발급받은 클라이언트 정보에 포함된 리디렉션 URI를 그대로 사용해야 합니다.

리디렉션 URI

  • Public Client: 모바일 앱의 경우 커스텀 스킴을 사용합니다 (예: yourapp://callback)
  • Confidential Client: 웹 애플리케이션의 경우 HTTPS URL을 사용합니다 (예: https://your-domain.com/callback)
  • 정확한 URI: 발급받은 클라이언트 정보에 명시된 정확한 리디렉션 URI를 사용해야 합니다

클라이언트 발급 신청

OAuth 클라이언트 발급을 원하시면 Checkable 서비스 개발자 지원팀에 문의하세요. 발급 신청 시 다음 정보를 포함해 주세요:
  • 애플리케이션 이름
  • 클라이언트 타입 (Public/Confidential)
  • 리디렉션 URI 목록
  • 연락처 정보

지원

OAuth 2.0 구현에 대한 도움이 필요하시면 Checkable 서비스 개발자 지원팀에 문의하세요.