Twenty는 사용자 대상 앱에는 권한 부여 코드 + PKCE를, 서버 간 액세스에는 클라이언트 자격 증명을 사용하여 OAuth 2.0을 구현합니다. 클라이언트는 RFC 7591에 따라 동적으로 등록되며 — 대시보드에서 수동 설정은 필요하지 않습니다.
OAuth 사용 시기
| 시나리오 | 인증 방식 |
|---|
| 내부 스크립트, 자동화 | API 키 |
| 사용자를 대신하여 동작하는 외부 앱 | OAuth — 권한 부여 코드 |
| 서버 간, 사용자 컨텍스트 없음 | OAuth — 클라이언트 자격 증명 |
| UI 확장이 포함된 Twenty 앱 | 앱 (OAuth는 자동으로 처리됩니다) |
클라이언트 등록
Twenty는 RFC 7591에 따라 동적 클라이언트 등록을 지원합니다. 수동 설정이 필요 없습니다 — 프로그래밍 방식으로 등록하세요:
POST /oauth/register
Content-Type: application/json
{
"client_name": "My Integration",
"redirect_uris": ["https://myapp.com/callback"],
"grant_types": ["authorization_code"],
"token_endpoint_auth_method": "client_secret_post"
}
응답:
{
"client_id": "abc123",
"client_secret": "secret456",
"client_name": "My Integration",
"redirect_uris": ["https://myapp.com/callback"]
}
client_secret을 안전하게 저장하세요 — 나중에 다시 조회할 수 없습니다.
| 범위 | 액세스 |
|---|
api | Core 및 Metadata API에 대한 전체 읽기/쓰기 액세스 |
프로필 | 인증된 사용자의 프로필 정보 읽기 |
범위를 공백으로 구분된 문자열로 요청: scope=api profile
권한 부여 코드 플로우
앱이 Twenty 사용자를 대신해 동작할 때 이 플로우를 사용하세요.
1. 사용자를 권한 부여 화면으로 리디렉션
GET /oauth/authorize?
client_id=YOUR_CLIENT_ID&
response_type=code&
redirect_uri=https://myapp.com/callback&
scope=api&
state=random_state_value&
code_challenge=CHALLENGE&
code_challenge_method=S256
| 매개변수 | 필수 | 설명 |
|---|
client_id | 예 | 등록된 클라이언트 ID |
response_type | 예 | 반드시 code여야 합니다 |
redirect_uri | 예 | 등록된 리디렉션 URI와 일치해야 합니다 |
scope | 아니요 | 공백으로 구분된 범위(기본값은 api) |
상태 | 권장 | CSRF 공격을 방지하기 위한 랜덤 문자열 |
code_challenge | 권장 | PKCE 챌린지(검증자 값의 SHA-256 해시, base64url 인코딩) |
code_challenge_method | 권장 | PKCE를 사용할 때는 S256이어야 합니다 |
사용자는 동의 화면을 보고 액세스를 승인하거나 거부합니다.
2. 콜백 처리
권한 부여 후, Twenty는 귀하의 redirect_uri로 다시 리디렉션합니다:
https://myapp.com/callback?code=AUTH_CODE&state=random_state_value
state가 보낸 값과 일치하는지 확인하세요.
3. 코드를 토큰으로 교환
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=AUTH_CODE&
redirect_uri=https://myapp.com/callback&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET&
code_verifier=YOUR_PKCE_VERIFIER
응답:
{
"access_token": "eyJhbG...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "dGhpcyBpcyBh..."
}
4. 액세스 토큰 사용
GET /rest/companies
Authorization: Bearer ACCESS_TOKEN
5. 만료 시 갱신
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&
refresh_token=YOUR_REFRESH_TOKEN&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET
클라이언트 자격 증명 플로우
사용자 상호작용이 없는 서버 간 통합의 경우:
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET&
scope=api
반환된 토큰은 특정 사용자에 연결되지 않고 워크스페이스 수준의 액세스를 가집니다.
서버 디스커버리
Twenty는 표준 디스커버리 엔드포인트에서 OAuth 구성을 게시합니다:
GET /.well-known/oauth-authorization-server
이 엔드포인트는 모든 엔드포인트, 지원되는 그랜트 타입, 범위 및 기능을 반환하며 — 범용 OAuth 클라이언트를 구축하는 데 유용합니다.
API 엔드포인트 요약
| 엔드포인트 | 목적 |
|---|
/.well-known/oauth-authorization-server | 서버 메타데이터 디스커버리 |
/oauth/register | 동적 클라이언트 등록 |
/oauth/authorize | 사용자 권한 부여 |
/oauth/token | 토큰 교환 및 갱신 |
| 환경 | 기본 URL |
|---|
| 클라우드 | https://api.twenty.com |
| 셀프 호스팅 | https://{your-domain} |
OAuth 대 API 키
| API 키 | OAuth |
|---|
| 설정 | 설정에서 생성 | 클라이언트 등록, 플로우 구현 |
| 사용자 컨텍스트 | 없음(워크스페이스 수준) | 특정 사용자의 권한 |
| 적합한 용도 | 스크립트, 내부 도구 | 외부 앱, 다중 사용자 통합 |
| 토큰 로테이션 | 수동 | 리프레시 토큰으로 자동 |
| 범위 지정 액세스 | 전체 API 액세스 | 범위를 통해 세분화된 액세스 |