OAuth 2.0 아이덴티티 프로바이더 API

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated

GitLab은 OAuth 2.0 프로토콜을 통해 사용자를 대신하여 GitLab 리소스에 접근할 수 있도록 서드 파티 서비스에 API를 제공합니다.

이를 위해 GitLab을 구성하려면
GitLab을 OAuth 2.0 인증 아이덴티티 프로바이더로 설정하기를 참조하세요.

이 기능은 doorkeeper Ruby gem을 기반으로 합니다.

교차 출처 리소스 공유

많은 /oauth 엔드포인트는 교차 출처 리소스 공유(CORS)를 지원합니다. GitLab 15.1부터는 다음 엔드포인트도 지원합니다:
CORS 사전 요청:

  • /oauth/revoke
  • /oauth/token
  • /oauth/userinfo

사전 요청에는 특정 헤더만 사용할 수 있습니다:

예를 들어, X-Requested-With 헤더는 사전 요청에 사용할 수 없습니다.

지원되는 OAuth 2.0 흐름

GitLab은 다음과 같은 인증 흐름을 지원합니다:

  • 코드 교환을 위한 증명 키(Proof Key for Code Exchange, PKCE) 사용한 인증 코드:
    가장 안전한 흐름입니다. PKCE가 없으면 모바일 클라이언트에서 클라이언트 비밀을 포함해야 하며, 클라이언트 및 서버 앱 모두에서 추천됩니다.

  • 인증 코드:
    안전하고 일반적인 흐름입니다. 안전한 서버 측 앱에 권장되는 옵션입니다.

  • 리소스 소유자 비밀번호 자격 증명:
    오직 안전하게 호스팅되는 1차 서비스에만 사용해야 합니다. GitLab은 이 흐름의 사용을 권장하지 않습니다.

  • 디바이스 인증 부여(GitLab 17.1 이상):
    브라우저 접근이 없는 장치에 맞춰진 안전한 흐름입니다. 인증 흐름을 완료하려면 보조 장치가 필요합니다.

OAuth 2.1의 초안 사양은 암시적 부여 및 리소스 소유자 비밀번호 자격 증명 흐름을 명시적으로 제외합니다.

모든 흐름이 작동하는 방법과 귀하의 사용 사례에 적합한 흐름을 선택하려면
OAuth RFC를 참조하세요.

인증 코드(PKCE가 있거나 없는)의 흐름은 /user_settings/applications 페이지를 통해 먼저 application이 등록되어야 합니다.

등록 중에 적절한 범위를 활성화하여 application이 접근할 수 있는 리소스의 범위를 제한할 수 있습니다. 생성 후에는
application 자격 증명인: Application ID 및 _Client Secret_을 받게 됩니다. _Client Secret_은 안전하게 보관해야 합니다.
또한 애플리케이션 아키텍처가 허용하는 경우 _Application ID_를 비밀로 유지하는 것이 유리합니다.

GitLab의 범위 목록은 공급자 문서를 참조하세요.

CSRF 공격 방지

리디렉션 기반 흐름을 보호하기 위해,
OAuth 사양은 요청 시마다 /oauth/authorize 엔드포인트에 대해 사용자 에이전트에 안전하게 바인딩된 “상태 매개변수에 포함된 일회용 CSRF 토큰”의 사용을 권장합니다.
이것은 CSRF 공격을 방지할 수 있습니다.

프로덕션에서 HTTPS 사용

프로덕션에서는 redirect_uri에 HTTPS를 사용하세요.

개발의 경우, GitLab은 안전하지 않은 HTTP 리디렉션 URI를 허용합니다.

OAuth 2.0이 보안을 전적으로 전송 계층에 기반하고 있기 때문에, 보호되지 않은
URI를 사용해서는 안 됩니다. 자세한 내용은 OAuth 2.0 RFCOAuth 2.0 위협 모델 RFC를 참조하세요.

다음 섹션에서는 각 흐름에 따라 인증을 얻는 방법에 대한 자세한 지침을 찾을 수 있습니다.

인증 코드와 함께 코드 교환을 위한 증명 키 (PKCE)

PKCE RFC에는 인증 요청부터 접근
토큰까지의 자세한 흐름 설명이 포함되어 있습니다. 다음 단계에서는 이 흐름의 구현을 설명합니다.

인증 코드와 함께하는 PKCE 흐름, 줄여서 PKCE는, 사용자로부터 비밀을
보호할 수 없는 공개 클라이언트에서 클라이언트 자격 증명의 OAuth 교환을
안전하게 수행할 수 있게 합니다. 이것은 비밀을 사용자가 볼 수 없도록
하는 것이 기술적으로 불가능한 단일 페이지 JavaScript 애플리케이션이나 기타
클라이언트 측 앱에 유리합니다.

흐름을 시작하기 전에 STATE, CODE_VERIFIERCODE_CHALLENGE를 생성하세요.

  • STATE는 클라이언트가 요청과 콜백 간의 상태를 유지하는 데 사용되는 예측할 수 없는 값입니다. CSRF 토큰으로도 사용해야 합니다.
  • CODE_VERIFIER는 길이가 43에서 128자 사이의 무작위 문자열로, A-Z, a-z, 0-9, -, ., _, ~ 문자를 사용합니다.
  • CODE_CHALLENGECODE_VERIFIER의 SHA256 해시를 URL 안전하게
    base64로 인코딩한 문자열입니다:
    • SHA256 해시는 인코딩하기 전에 이진 형식이어야 합니다.
    • Ruby에서는 Base64.urlsafe_encode64(Digest::SHA256.digest(CODE_VERIFIER), padding: false)로 설정할 수 있습니다.
    • 참고로, CODE_VERIFIER 문자열 ks02i3jdikdo2k0dkfodf3m39rjfjsdk0wk349rj3jrhf를 해시하고
      위의 Ruby 코드를 사용하여 인코딩하면 CODE_CHALLENGE 문자열
      2i0WFA-0AerkjQm4X4oDEhqA17QIAKNjXpagHBXmO_U가 생성됩니다.
  1. 인증 코드 요청. 이를 위해, 사용자를 다음 쿼리 매개 변수가 포함된
    /oauth/authorize 페이지로 리디렉션해야 합니다:

    https://gitlab.example.com/oauth/authorize?client_id=APP_ID&redirect_uri=REDIRECT_URI&response_type=code&state=STATE&scope=REQUESTED_SCOPES&code_challenge=CODE_CHALLENGE&code_challenge_method=S256
    

    이 페이지는 사용자에게 REQUESTED_SCOPES에 지정된 범위를 기반으로
    앱이 자신의 계정에 접근할 수 있도록 요청을 승인하도록 요청합니다.
    사용자는 이후 지정된 REDIRECT_URI로 리디렉션됩니다. scope 매개 변수
    사용자와 관련된 범위의 공백으로 구분된 목록입니다.
    예를 들어, scope=read_user+profileread_userprofile 범위를 요청합니다.
    리디렉션에는 인증 code가 포함되며, 예를 들면 다음과 같습니다:

    https://example.com/oauth/redirect?code=1234567890&state=STATE
    
  2. 이전 요청에서 반환된 인증 code(다음 예제에서 RETURNED_CODE로 표시됨)를 사용하여
    HTTP 클라이언트를 통해 access_token을 요청할 수 있습니다. 다음 예제는 Ruby의 rest-client를 사용합니다:

    parameters = 'client_id=APP_ID&code=RETURNED_CODE&grant_type=authorization_code&redirect_uri=REDIRECT_URI&code_verifier=CODE_VERIFIER'
    RestClient.post 'https://gitlab.example.com/oauth/token', parameters
    

    예 응답:

    {
     "access_token": "de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54",
     "token_type": "bearer",
     "expires_in": 7200,
     "refresh_token": "8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1",
     "created_at": 1607635748
    }
    
  3. 새로운 access_token을 가져오기 위해 refresh_token 매개 변수를 사용하세요.
    Refresh token은 access_token 자체가 만료된 후에도 사용할 수 있습니다.
    이 요청은:

    • 기존의 access_tokenrefresh_token을 무효화합니다.
    • 응답으로 새로운 토큰을 보냅니다.
      parameters = 'client_id=APP_ID&refresh_token=REFRESH_TOKEN&grant_type=refresh_token&redirect_uri=REDIRECT_URI&code_verifier=CODE_VERIFIER'
      RestClient.post 'https://gitlab.example.com/oauth/token', parameters
    

    예 응답:

    {
      "access_token": "c97d1fe52119f38c7f67f0a14db68d60caa35ddc86fd12401718b649dcfa9c68",
      "token_type": "bearer",
      "expires_in": 7200,
      "refresh_token": "803c1fd487fec35562c205dac93e9d8e08f9d3652a24079d704df3039df1158f",
      "created_at": 1628711391
    }
    

참고:
redirect_uri는 원래 인증 요청에 사용된 redirect_uri와 일치해야 합니다.

이제 접근 토큰을 사용하여 API에 요청할 수 있습니다.

인증 코드 흐름

note
RFC 사양을 확인하여
자세한 흐름 설명을 참조하세요.

인증 코드 흐름은 본질적으로
PKCE를 사용하는 인증 코드 흐름과 동일합니다.

흐름을 시작하기 전에 STATE를 생성하세요. 이는 요청과 콜백 간의 상태를 유지하기 위해 클라이언트가 사용하는 예측할 수 없는 값입니다. 또한 CSRF 토큰으로 사용해야 합니다.

  1. 인증 코드를 요청합니다. 이를 위해 사용자를 다음 쿼리 매개변수로 /oauth/authorize 페이지로 리디렉션해야 합니다:

    https://gitlab.example.com/oauth/authorize?client_id=APP_ID&redirect_uri=REDIRECT_URI&response_type=code&state=STATE&scope=REQUESTED_SCOPES
    

    이 페이지는 사용자에게 REQUESTED_SCOPES에 명시된 범위에 따라 앱이 계정에 접근하는 요청을 승인하도록 요청합니다. 사용자는 지정된 REDIRECT_URI로 다시 리디렉션됩니다.
    scope 매개변수은 사용자가 승인한 범위의 공백으로 구분된 목록입니다.
    예를 들어, scope=read_user+profileread_userprofile 범위를 요청합니다.
    리디렉션에는 인증 code가 포함됩니다. 예를 들면:

    https://example.com/oauth/redirect?code=1234567890&state=STATE
    
  2. 이전 요청에서 반환된 인증 code (다음 예제에서 RETURNED_CODE로 표시된)를 사용하여
    어떠한 HTTP 클라이언트를 사용하여 access_token을 요청할 수 있습니다.
    다음 예제는 Ruby의 rest-client를 사용합니다:

    parameters = 'client_id=APP_ID&client_secret=APP_SECRET&code=RETURNED_CODE&grant_type=authorization_code&redirect_uri=REDIRECT_URI'
    RestClient.post 'https://gitlab.example.com/oauth/token', parameters
    

    예제 응답:

    {
     "access_token": "de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54",
     "token_type": "bearer",
     "expires_in": 7200,
     "refresh_token": "8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1",
     "created_at": 1607635748
    }
    
  3. access_token을 가져오려면 refresh_token 매개변수를 사용하세요.
    access_token이 만료된 후에도 refresh token을 사용할 수 있습니다. 이 요청은:

    • 기존의 access_tokenrefresh_token을 무효화합니다.
    • 응답에 새 토큰을 전송합니다.
      parameters = 'client_id=APP_ID&client_secret=APP_SECRET&refresh_token=REFRESH_TOKEN&grant_type=refresh_token&redirect_uri=REDIRECT_URI'
      RestClient.post 'https://gitlab.example.com/oauth/token', parameters
    

    예제 응답:

    {
      "access_token": "c97d1fe52119f38c7f67f0a14db68d60caa35ddc86fd12401718b649dcfa9c68",
      "token_type": "bearer",
      "expires_in": 7200,
      "refresh_token": "803c1fd487fec35562c205dac93e9d8e08f9d3652a24079d704df3039df1158f",
      "created_at": 1628711391
    }
    
note
redirect_uri는 원래 인증 요청에서 사용된 redirect_uri와 일치해야 합니다.

이제 반환된 액세스 토큰과 함께 API 요청을 할 수 있습니다.

디바이스 인증 승인 흐름

플래그:
이 기능의 사용 가능성은 기능 플래그에 의해 제어됩니다.
자세한 내용은 기록을 참조하세요.

참고:
RFC 사양에서 디바이스 인증 승인 흐름에 대한 상세한 설명을 확인하세요. 브라우저 로그인에서 토큰 응답까지의 과정이 포함됩니다.

디바이스 인증 승인 흐름은 브라우저 상호작용이 불가능한 입력 제한 장치에서 GitLab 신원을 안전하게 인증할 수 있게 해줍니다.

따라서 디바이스 인증 승인 흐름은 헤드리스 서버 또는 UI가 없거나 제한된 다른 장치에서 GitLab 서비스를 사용하려는 사용자에게 이상적입니다.

  1. 디바이스 인증을 요청하기 위해, 입력 제한 장치 클라이언트에서 https://gitlab.example.com/oauth/authorize_device로 요청이 전송됩니다. 예를 들어:

      parameters = 'client_id=UID&scope=read'
      RestClient.post 'https://gitlab.example.com/oauth/authorize_device', parameters
    

    성공적인 요청 후, verification_uri가 포함된 응답이 사용자에게 반환됩니다. 예를 들어:

    {
        "device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
        "user_code": "0A44L90H",
        "verification_uri": "https://gitlab.example.com/oauth/device",
        "verification_uri_complete": "https://gitlab.example.com/oauth/device?user_code=0A44L90H",
        "expires_in": 300,
        "interval": 5
    }
    
  2. 디바이스 클라이언트는 요청한 사용자에게 응답의 user_codeverification_uri를 표시합니다. 해당 사용자는 그런 다음 브라우저 접근이 가능한 보조 장치에서:
    1. 제공된 URI로 이동합니다.
    2. 사용자 코드를 입력합니다.
    3. 프롬프트에 따라 인증을 완료합니다.
  3. verification_uriuser_code를 표시한 직후, 디바이스 클라이언트는 초기 응답에서 반환된 관련 device_code로 토큰 엔드포인트를 폴링하기 시작합니다:

    parameters = 'grant_type=urn:ietf:params:oauth:grant-type:device_code
    &device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS
    &client_id=1406020730'
    RestClient.post 'https://gitlab.example.com/oauth/token', parameters
    
  4. 디바이스 클라이언트는 토큰 엔드포인트로부터 응답을 수신합니다. 인증이 성공적이었다면, 성공 응답이 반환되고, 그렇지 않으면 오류 응답이 반환됩니다.
    잠재적인 오류 응답은 다음 두 가지로 분류됩니다:
    • OAuth 인증 프레임워크 액세스 토큰 오류 응답에서 정의된 오류.
    • 여기에서 설명하는 디바이스 인증 승인 흐름에 특정한 오류.

    디바이스 흐름에 특정한 오류 응답은 다음 콘텐츠에 설명되어 있습니다.
    각 잠재적 응답에 대한 자세한 내용은 관련 디바이스 인증 승인에 대한 RFC 사양인증 토큰에 대한 RFC 사양을 참조하세요.

    예제 응답:

    {
      "error": "authorization_pending",
      "error_description": "..."
    }
    

    이 응답을 수신하면, 디바이스 클라이언트는 계속해서 폴링을 진행합니다.

    폴링 간격이 너무 짧으면, 느린 속도의 오류 응답이 반환됩니다. 예를 들면:

    {
      "error": "slow_down",
      "error_description": "..."
    }
    

    이 응답을 수신하면, 디바이스 클라이언트는 폴링 속도를 줄이고 새로운 속도로 계속 폴링합니다.

    디바이스 코드가 인증 완료 전에 만료되면, 만료된 토큰 오류 응답이 반환됩니다. 예를 들어:

    {
      "error": "expired_token",
      "error_description": "..."
    }
    

    그 시점에서 디바이스 클라이언트는 중지하고 새로운 디바이스 인증 요청을 시작해야 합니다.

    인증 요청이 거부되면, 접근 거부 오류 응답이 반환됩니다. 예를 들어:

    {
      "error": "access_denied",
      "error_description": "..."
    }
    

    인증 요청이 거부되었습니다. 사용자는 자격 증명을 확인하거나 시스템 관리자에게 문의해야 합니다.

  5. 사용자가 성공적으로 인증되면, 성공 응답이 반환됩니다:

    {
        "access_token": "TOKEN",
        "token_type": "Bearer",
        "expires_in": 7200,
        "scope": "read",
        "created_at": 1593096829
    }
    

이 시점에서 디바이스 인증 흐름이 완료됩니다. 반환된 access_token은 GitLab 리소스에 접근할 때 사용자 신원을 인증하는 데 제공될 수 있습니다. 예를 들어, HTTPS를 통해 클론하거나 API에 접근할 때 사용할 수 있습니다.

클라이언트 측 디바이스 흐름을 구현하는 샘플 애플리케이션은 다음에서 찾을 수 있습니다: https://gitlab.com/johnwparent/git-auth-over-https.

리소스 소유자 비밀번호 자격 증명 흐름

note
RFC 스펙을 확인하여
상세 흐름 설명을 참조하세요.
note
리소스 소유자 비밀번호 자격 증명은
2단계 인증이 활성화된 사용자에게는 비활성화됩니다.
이 사용자들은 대신 개인 액세스 토큰을 사용하여 API에 접근할 수 있습니다.
note
GitLab 인스턴스가 비밀번호 자격 증명 흐름을 지원하려면
HTTP(S)에서 Git에 대한 비밀번호 인증 허용
체크박스가 선택되어 있어야 합니다.

이 흐름에서, 리소스 소유자 자격 증명(사용자 이름 및 비밀번호)에 대한 교환으로 토큰이 요청됩니다.

자격 증명은 다음과 같은 경우에만 사용해야 합니다:

  • 리소스 소유자와 클라이언트 간에 신뢰도가 높을 경우. 예를 들어, 클라이언트가 기기 운영 체제의 일부이거나 매우 특권이 있는 애플리케이션인 경우입니다.
  • 다른 인증 부여 유형을 사용할 수 없는 경우(예: 인증 코드 등).
caution
절대 사용자의 자격 증명을 저장하지 마십시오.
신뢰할 수 있는 환경에 클라이언트가 배포될 때만 이 인증 부여 유형을 사용하십시오.
99%의 경우
개인 액세스 토큰이 더 나은 선택입니다.

이 인증 부여 유형은 클라이언트가 리소스 소유자 자격 증명에 직접 접근해야 하지만,
리소스 소유자 자격 증명은 단일 요청에만 사용되며 액세스 토큰으로 교환됩니다.
이 인증 부여 유형은 리소스 소유자 자격 증명을 미래에 사용할 필요 없이
장기간 사용 가능한 액세스 토큰 또는 새로 고침 토큰과 교환함으로써
클라이언트가 자격 증명을 저장할 필요성을 제거할 수 있습니다.

액세스 토큰을 요청하려면, 다음 매개변수와 함께 /oauth/token에 POST 요청을 해야 합니다:

{
  "grant_type"    : "password",
  "username"      : "user@example.com",
  "password"      : "secret"
}

예시 cURL 요청:

echo 'grant_type=password&username=<your_username>&password=<your_password>' > auth.txt
curl --data "@auth.txt" --request POST "https://gitlab.example.com/oauth/token"

등록된 OAuth 애플리케이션과 함께 이 인증 부여 흐름을 사용할 수도 있습니다.
애플리케이션의 client_idclient_secret을 사용한 HTTP 기본 인증을 사용하여:

echo 'grant_type=password&username=<your_username>&password=<your_password>' > auth.txt
curl --data "@auth.txt" --user client_id:client_secret \
     --request POST "https://gitlab.example.com/oauth/token"

그런 다음, 액세스 토큰을 포함하는 응답을 받게 됩니다:

{
  "access_token": "1f0af717251950dbd4d73154fdf0a474a5c5119adad999683f5b450c460726aa",
  "token_type": "bearer",
  "expires_in": 7200
}

기본적으로, 액세스 토큰의 범위는 api로 설정되어 있어 전체 읽기/쓰기 접근을 제공합니다.

테스트를 위해 oauth2 Ruby gem을 사용할 수 있습니다:

client = OAuth2::Client.new('the_client_id', 'the_client_secret', :site => "https://example.com")
access_token = client.password.get_token('user@example.com', 'secret')
puts access_token.token

access token으로 GitLab API에 접근하기

access token을 사용하면 사용자를 대신하여 API에 요청을 보낼 수 있습니다.
토큰을 GET 매개변수로 전달할 수 있습니다:

GET https://gitlab.example.com/api/v4/user?access_token=OAUTH-TOKEN

또는 토큰을 Authorization 헤더에 넣을 수도 있습니다:

curl --header "Authorization: Bearer OAUTH-TOKEN" "https://gitlab.example.com/api/v4/user"

HTTPS로 Git에 액세스하기 access token

read_repository 또는 write_repository 범위를 가진 토큰은 HTTPS를 통해 Git에 액세스할 수 있습니다. 암호로 토큰을 사용하세요.

사용자 이름을 임의의 문자열로 설정할 수 있습니다. oauth2를 사용해야 합니다:

https://oauth2:<your_access_token>@gitlab.example.com/project_path/project_name.git

또는 Git 자격 증명 헬퍼를 사용하여 OAuth로 GitLab에 인증할 수 있습니다. 이는 OAuth 토큰 갱신을 자동으로 처리합니다.

토큰 정보 검색

토큰의 세부 정보를 확인하려면 Doorkeeper gem에서 제공하는 token/info 엔드포인트를 사용하세요. 자세한 내용은 /oauth/token/info를 참조하세요.

액세스 토큰을 다음과 같이 제공해야 합니다:

  • 매개변수로:

    GET https://gitlab.example.com/oauth/token/info?access_token=<OAUTH-TOKEN>
    
  • Authorization 헤더에:

    curl --header "Authorization: Bearer <OAUTH-TOKEN>" "https://gitlab.example.com/oauth/token/info"
    

다음은 응답 예입니다:

{
    "resource_owner_id": 1,
    "scope": ["api"],
    "expires_in": null,
    "application": {"uid": "1cb242f495280beb4291e64bee2a17f330902e499882fe8e1e2aa875519cab33"},
    "created_at": 1575890427
}

사용 중지된 필드

scopesexpires_in_seconds 필드는 응답에 포함되지만 이제 사용되지 않습니다. scopes 필드는 scope의 별칭이며, expires_in_seconds 필드는 expires_in의 별칭입니다. 자세한 내용은 Doorkeeper API 변경 사항을 참조하세요.

토큰 취소

토큰을 취소하려면 revoke 엔드포인트를 사용하세요. API는 성공을 나타내기 위해 200 응답 코드와 빈 JSON 해시를 반환합니다.

parameters = 'client_id=APP_ID&client_secret=APP_SECRET&token=TOKEN'
RestClient.post 'https://gitlab.example.com/oauth/revoke', parameters

OAuth 2.0 토큰과 GitLab 레지스트리

표준 OAuth 2.0 토큰은 GitLab 레지스트리에 대한 다양한 접근 수준을 지원합니다. 이들은: