OAuth 2.0 Identity Provider API
- プラン: Free、Premium、Ultimate
- 提供形態: GitLab.com、GitLab Self-Managed、GitLab Dedicated
このAPIを使用すると、サードパーティサービスがOAuth 2.0プロトコルを使用して、ユーザーのGitLabリソースにアクセスできるようになります。詳細については、GitLabをOAuth 2.0認証用のIdentity Providerとして設定するを参照してください。
この機能は、doorkeeper Ruby gemに基づいています。
クロスオリジンリソース共有
多くの/oauthエンドポイントは、クロスオリジンリソース共有(CORS)をサポートしています。GitLab 15.1以降、次のエンドポイントもCORSプリフライトリクエストをサポートしています:
/oauth/revoke/oauth/token/oauth/userinfo
プリフライトリクエストには、特定のヘッダーのみを使用できます:
- シンプルなリクエストにリストされているヘッダー
Authorizationヘッダー
たとえば、X-Requested-Withヘッダーはプリフライトリクエストには使用できません。
サポートされているOAuth 2.0フロー
GitLabは、次の認証フローをサポートしています:
- Authorization code with Proof Key for Code Exchange (PKCE)(Proof Key for Code Exchange(PKCE)を使用した認証コード): もっとも安全です。PKCEを使用しない場合、モバイルクライアントにクライアントシークレットを含める必要があり、クライアントアプリとサーバーアプリの両方でPKCEの利用が推奨されています。
- Authorization code(認証コード): 安全で一般的なフローです。安全なサーバーサイドアプリに推奨される選択肢です。
- Resource owner password credentials(リソースオーナーパスワードクレデンシャル): 安全にホストされているファーストパーティサービスonly(のみ)に使用します。GitLabではこのフローの使用を推奨していません。
- Device Authorization Grant(GitLab 17.1以降)ブラウザーへのアクセスがないデバイスへのセキュアフロー。この認証フローを完了するにはセカンダリデバイスが必要です。
OAuth 2.1のドラフト仕様では、インプリシットグラントフローとリソースオーナーパスワードクレデンシャルフローの両方が明示的に除外されています。
OAuth RFCを参照して、すべてのフローの仕組みを理解し、各自のユースケースに適したフローを選択してください。
認証コードフローでは(PKCEの有無にかかわらず)、最初にユーザーのアカウントの/user_settings/applicationsページからapplicationを登録する必要があります。登録中に適切なスコープを有効にすることで、applicationがアクセスできるリソースの範囲を制限できます。作成時にapplication認証情報: (アプリケーションID_と_クライアントシークレット)を取得します。_クライアントシークレット_をmust be kept secure(安全に保管する必要があります)。アプリケーションアーキテクチャで許可されている場合は、_アプリケーションID_もシークレットにしておくことをおすすめします。
GitLabのスコープのリストについては、プロバイダーのドキュメントを参照してください。
CSRF攻撃を防ぐ
リダイレクトベースのフローを保護するために、OAuth仕様では、/oauth/authorizeエンドポイントへの各リクエストで、「ユーザーエージェントに安全にバインドされたstateパラメータで伝送される1回限りのCSRFトークン」を使用することが推奨されています。これにより、CSRF攻撃を防ぐことができます。
本番環境でHTTPSを使用する
本番環境ではredirect_uriにHTTPSを使用します。GitLabでは、開発環境の場合には安全でないHTTPリダイレクトURIを使用することを許可しています。
OAuth 2.0のセキュリティは完全にトランスポートレイヤに基づいているので、保護されていないURIは使用すべきではありません。詳細については、OAuth 2.0 RFCとOAuth 2.0 Threat Model RFCを参照してください。
以下のセクションでは、各フローで認証を取得するための詳しい手順を説明します。
Proof Key for Code Exchange(PKCE)を使用した認証コード
PKCE RFCには、認証リクエストからアクセストークンまで、詳細なフローの説明が含まれています。以下の手順では、GitLabでのフローの実装について説明します。
PKCEを使用した認証コードフロー(略してPKCE)を使用すると、_クライアントシークレット_へのアクセスを必要とせずに、パブリッククライアントでアクセストークンのクライアント認証情報のOAuth交換を安全に実行できます。これにより、ユーザーからシークレットを保持することが技術的に不可能なシングルページJavaScriptアプリケーションやその他のクライアント側アプリで、PKCEフローが有利になります。
フローを開始する前に、STATE、CODE_VERIFIER、およびCODE_CHALLENGEを生成します。
STATEは、リクエストとコールバックの間で状態を維持するためにクライアントが使用する予測不能な値です。これをCSRFトークンとしても使用する必要があります。CODE_VERIFIERは、長さが43 – 128文字のランダムな文字列で、文字A-Z、a-z、0-9、-、.、_、および~を使用できます。CODE_CHALLENGEは、CODE_VERIFIERのSHA256ハッシュのURLセーフなbase64エンコード文字列です:- SHA256ハッシュは、エンコード前にバイナリ形式である必要があります。
- Rubyでは、
Base64.urlsafe_encode64(Digest::SHA256.digest(CODE_VERIFIER), padding: false)を使用してこれを設定できます。 - 参考までに、上記のRubyスニペットを使用してハッシュ化およびエンコードした場合、
CODE_VERIFIERの文字列ks02i3jdikdo2k0dkfodf3m39rjfjsdk0wk349rj3jrhfにより、CODE_CHALLENGEの文字列2i0WFA-0AerkjQm4X4oDEhqA17QIAKNjXpagHBXmO_Uが生成されます。
認証コードをリクエストします。これを行うには、次のクエリパラメータを指定して、ユーザーを
/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&root_namespace_id=ROOT_NAMESPACE_IDこのページではユーザーに対し、
REQUESTED_SCOPESで指定されたスコープに基づいて、アプリからアカウントへのアクセスリクエストを承認するように求めます。その後、ユーザーは指定されたREDIRECT_URIにリダイレクトされます。スコープパラメータは、ユーザーに関連付けられているスコープのスペース区切りのリストです。たとえばscope=read_user+profileは、read_userスコープとprofileスコープをリクエストします。root_namespace_idは、プロジェクトに関連付けられたルートネームスペースIDです。このオプションのパラメータは、関連付けられたグループにSAML SSOが設定されている場合に使用する必要があります。リダイレクトには認証codeが含まれます。次に例を示します:https://example.com/oauth/redirect?code=1234567890&state=STATE前のリクエストから返された認証
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 }新しい
access_tokenを取得するには、refresh_tokenパラメータを使用します。リフレッシュトークンは、access_token自体が期限切れになった後でも使用可能です。このリクエストは次の処理を行います:- 既存の
access_tokenとrefresh_tokenを無効にします。 - 応答で新しいトークンを送信します。
parameters = 'client_id=APP_ID&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 }- 既存の
redirect_uriは、元の認証リクエストで使用されたredirect_uriと一致している必要があります。
これで、アクセストークンを使用してAPIにリクエストを行えるようになります。
認証コードフロー
詳細なフローの説明については、RFC仕様を確認してください。
この認証コードフローは、基本的にPKCEを使用した認証コードフローと同じです。
フローを開始する前に、STATEを生成します。これは、リクエストとコールバックの間で状態を維持するためにクライアントが使用する予測不能な値です。これをCSRFトークンとしても使用する必要があります。
認証コードをリクエストします。これを行うには、次のクエリパラメータを指定して、ユーザーを
/oauth/authorizeページにリダイレクトする必要があります:https://gitlab.example.com/oauth/authorize?client_id=APP_ID&redirect_uri=REDIRECT_URI&response_type=code&state=STATE&scope=REQUESTED_SCOPES&root_namespace_id=ROOT_NAMESPACE_IDこのページではユーザーに対し、
REQUESTED_SCOPESで指定されたスコープに基づいて、アプリからアカウントへのアクセスリクエストを承認するように求めます。その後、ユーザーは指定されたREDIRECT_URIにリダイレクトされます。スコープパラメータは、ユーザーに関連付けられているスコープのスペース区切りのリストです。たとえばscope=read_user+profileは、read_userスコープとprofileスコープをリクエストします。root_namespace_idは、プロジェクトに関連付けられたルートネームスペースIDです。このオプションのパラメータは、関連付けられたグループにSAML SSOが設定されている場合に使用する必要があります。リダイレクトには認証codeが含まれます。次に例を示します:https://example.com/oauth/redirect?code=1234567890&state=STATE前のリクエストから返された認証
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 }新しい
access_tokenを取得するには、refresh_tokenパラメータを使用します。リフレッシュトークンは、access_token自体が期限切れになった後でも使用可能です。このリクエストは次の処理を行います:- 既存の
access_tokenとrefresh_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 }- 既存の
redirect_uriは、元の認証リクエストで使用されたredirect_uriと一致している必要があります。
これで、返されたアクセストークンを使用してAPIにリクエストを行えるようになります。
デバイス認可グラントフロー
デバイス認可リクエストから、ブラウザーログインからのトークン応答まで、デバイス認可グラントフローの詳細な説明については、RFC仕様を確認してください。
デバイス認可グラントフローを使うことで、ブラウザ操作ができない入力制限のあるデバイスからでも、安全にGitLabのアイデンティティ認証が可能になります。
そのため、このフローはヘッドレスサーバーや、UIがない、あるいは限られているデバイスからGitLabのサービスを利用しようとするユーザーに最適です。
デバイス認可をリクエストするには、インプットが制限されているデバイスクライアントから
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 }デバイスクライアントでは、応答の
user_codeとverification_uriがリクエストユーザーに対して表示されます。次に、ブラウザにアクセスできるセカンダリデバイスでユーザーが次の操作を実行します:- 提供されたURIに移動します。
- ユーザーコードを入力します。
- プロンプトに従って認証を完了します。
デバイスクライアントは、
verification_uriとuser_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デバイスクライアントは、トークンエンドポイントから応答を受信します。認証が成功した場合は成功応答が返され、それ以外の場合はエラー応答が返されます。返される可能性があるエラー応答は、次のいずれかに分類されます:
- OAuth認可フレームワークアクセストークンのエラー応答によって定義されたもの。
- ここで説明するデバイス認可グラントフローに固有のもの。デバイスフローに固有のエラー応答については、以降で説明します。返される可能性がある応答の詳細については、関連するデバイス認可グラントのRFC仕様と認証トークンのRFC仕様を参照してください。
レスポンス例:
{ "error": "authorization_pending", "error_description": "..." }この応答を受信すると、デバイスクライアントはポーリングを続行します。
ポーリングの間隔が短すぎると、スローダウンエラー応答が返されます。例:
{ "error": "slow_down", "error_description": "..." }この応答を受信すると、デバイスクライアントはポーリングレートを下げ、新しいレートでポーリングを続行します。
認証が完了する前にデバイスコードが期限切れになると、期限切れトークンエラー応答が返されます。例:
{ "error": "expired_token", "error_description": "..." }この時点でデバイスクライアントは停止し、新しいデバイス認可リクエストを開始します。
認証リクエストが拒否された場合、アクセス拒否エラー応答が返されます。例:
{ "error": "access_denied", "error_description": "..." }認証リクエストが拒否されました。ユーザーは自分の認証情報を確認するか、システム管理者に連絡する必要があります。
ユーザーが正常に認証されると、成功応答が返されます:
{ "access_token": "TOKEN", "token_type": "Bearer", "expires_in": 7200, "scope": "read", "created_at": 1593096829 }
この時点でデバイス認証フローは完了です。返されたaccess_tokenトークンは、HTTPS経由での複製やAPIへのアクセスなど、GitLabリソースにアクセスするときに、ユーザーアイデンティティを認証するためにGitLabに提供できます。
クライアント側のデバイスフローを実装するサンプルアプリケーションは、https://gitlab.com/johnwparent/git-auth-over-httpsにあります。
リソースオーナーパスワードクレデンシャルフロー
詳細なフローの説明については、RFC仕様を確認してください。
リソースオーナーパスワードクレデンシャルは、2要素認証が有効になっているユーザーと、グループに対してパスワード認証が無効になっている エンタープライズユーザーに対しては無効になっています。これらのユーザーは、代わりにパーソナルアクセストークンを使用してAPIにアクセスできます。
パスワード認証情報フローをサポートするため、GitLabインスタンスでGit over HTTP(S) のパスワード認証を許可するチェックボックスがオンになっていることを確認してください。
このフローでは、リソースオーナー認証情報(ユーザー名とパスワード)と引き換えにトークンがリクエストされます。
この認証情報は、次の場合にのみ使用してください:
- リソースオーナーとクライアントの間に高度な信頼関係がある場合。たとえば、クライアントがデバイスオペレーティングシステムまたは高度な特権付きアプリケーションの一部である場合などです。
- ほかの認可付与タイプ(認証コードなど)は使用できません。
ユーザーの認証情報を保存しないでください。また、信頼できる環境にクライアントがデプロイされている場合にのみ、この付与タイプを使用してください。ほとんどのケースで、パーソナルアクセストークンの方が適しています。
この付与タイプでも、リソースオーナー認証情報へのクライアントの直接アクセスが必要ですが、リソースオーナー認証情報は1つのリクエストに使用され、アクセストークンと交換されます。この付与タイプを使用すると、認証情報を有効期間の長いアクセストークンまたはリフレッシュトークンと交換することで、クライアントが将来使用するためにリソースオーナー認証情報を保存する必要がなくなります。
アクセストークンをリクエストするには、/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_idとclient_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.tokenaccess 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"access tokenを使用してHTTPS経由でGitにアクセスする
スコープが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>ヘッダーに指定する:
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
}非推奨のフィールド
フィールドscopesとexpires_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', parametersOAuth 2.0トークンとGitLabレジストリ
標準のOAuth 2.0トークンは、GitLabの各種レジストリに対して異なるレベルのアクセスをサポートします。これらのトークンは、下記のとおり振る舞います:
- 下記のものに対するユーザーによる認証を許可しません:
- GitLabコンテナレジストリ
- GitLabパッケージレジストリにリストされているパッケージ
- 仮想レジストリ
- ユーザーによるコンテナレジストリAPIを介したレジストリの取得、リスト、および削除を許可します。
- ユーザーによるMaven仮想レジストリAPIを介したレジストリオブジェクトの取得、一覧表示、および削除を許可します。