- クロスオリジンリソース共有
- サポートされる OAuth 2.0 フロー
- を使って GitLab API にアクセスします。
access token
- を使って HTTPS で Git にアクセスします。
access token
- トークン情報の取得
- トークンの取り消し
- OAuth 2.0 トークンと GitLab レジストリ
OAuth 2.0 ID プロバイダ API
GitLabは、OAuth 2.0プロトコルでサードパーティのサービスがユーザーに代わってGitLabリソースにアクセスするためのAPIを提供しています。
GitLabをこのように設定するには、OAuth 2.0認証IDプロバイダとしてGitLabを設定するをご覧ください。
この機能は、doorkeeper Ruby gem をベースにしています。
クロスオリジンリソース共有
GitLab 15.1で導入されたCORSプリフライトリクエストサポート。
多くの/oauth
エンドポイントは、クロスオリジンリソース共有をサポートしています(CORS)。GitLab 15.1からは、以下のエンドポイントもCORSプリフライトリクエストをサポートしています:
/oauth/revoke
/oauth/token
/oauth/userinfo
プリフライトリクエストに使用できるのは特定のヘッダーのみです:
- 単純なリクエストにリストされているヘッダ。
-
Authorization
ヘッダ。
例えば、X-Requested-With
ヘッダーはプリフライトリクエストには使えません。
サポートされる OAuth 2.0 フロー
GitLabは以下の作成者フローをサポートしています:
- Proof Key for Code Exchangeによる認証コード(PKCE): 最もセキュリティが高いです。PKCEがなければ、モバイルクライアントにクライアントシークレットを含める必要があります。
- 作成者コード:セキュアで一般的なフロー。セキュアなサーバーサイドアプリに推奨。
- リソースオーナーのパスワード認証情報:セキュアにホストされたファーストパーティのサービスにのみ使用します。GitLabはこのフローを使用しないことを推奨します。
Device Authorization Grant はサポートされていません。イシュー332682ではサポートの追加を提案しています。
OAuth 2.1のドラフト仕様では、暗黙的グラントとリソースオーナーパスワードクレデンシャルの両方のフローが特に省略されています。
OAuthのRFCを参照し、これらのフローがどのように動作するのかを調べ、あなたのユースケースに適したものを選んでください。
作成者コード(PKCE の有無にかかわらず)フローでは、まずユーザーアカウントの/profile/applications
ページからapplication
を登録する必要があります。登録の際、適切なスコープを有効にすることで、application
アクセス application
できるリソースの範囲を制限することができます。application
作成時に application
認証情報をapplication
取得 application
します:アプリケーション ID_と_クライアントシークレット_です。_クライアントシークレットは セキュアに保たれなければなりません。また、アプリケーションアーキテクチャが許す限り、_アプリケーション ID_は秘密にしておく方が有利です。
GitLab のスコープ一覧については、プロバイダのドキュメントを参照してください。
CSRF攻撃を防ぐ
リダイレクトベースのフローを保護するために、OAuth 仕様では、/oauth/authorize
エンドポイントへの各リクエストで、”ユーザーエージェントにセキュアにバインドされた、state パラメータに格納された One-time use CSRF トークン” を使用することを推奨しています。これによりCSRF 攻撃を防ぐことができます。
本番環境で HTTPS を使用
本番環境では、redirect_uri
に HTTPS を使用してください。開発者向けには、GitLabは安全でないHTTPリダイレクトURIを許可しています。
OAuth 2.0のセキュリティは完全にトランスポート層に基づいているので、保護されていないURIを使うべきではありません。詳細については、OAuth 2.0 RFCと OAuth 2.0 Threat Model RFCを参照してください。
以下のセクションでは、各フローで作成者を認証する方法について詳しく説明します。
コード交換のためのプルーフキー付き作成者コード(PKCE)
PKCE RFCには、作成者からアクセストークンまでの詳細なフローが記述されています。以下のステップでは、このフローの実装を説明します。
PKCEフローを用いた認証コード(Authorization code with PKCE、略してPKCE)は、_クライアントシークレットへの_アクセスを一切必要とせずに、公開クライアント上でアクセストークンとクライアント認証情報のOAuth交換をセキュアに行うことを可能にします。このため、PKCEフローはシングルページのJavaScriptアプリや、ユーザーからシークレットを守ることが技術的に不可能なその他のクライアントサイドアプリに有利です。
フローを開始する前に、STATE
、CODE_VERIFIER
、CODE_CHALLENGE
を生成してください。
-
STATE
は、リクエストとコールバックの間で状態をメンテナーするためにクライアントが使用する、予測できない値です。また、CSRFトークンとしても使われます。 -
CODE_VERIFIER
は 43 文字から 128 文字の間のランダムな文字列で、A-Z
,a-z
,0-9
,-
,.
,_
,~
を使用します。 -
CODE_CHALLENGE
のSHA256ハッシュをURLセーフなbase64エンコードした文字列です。CODE_VERIFIER
- SHA256ハッシュはエンコードする前にバイナリ形式にしておく必要があります。
- Rubyでは、
Base64.urlsafe_encode64(Digest::SHA256.digest(CODE_VERIFIER), padding: false)
. - 参考までに、
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
このページでは、
REQUESTED_SCOPES
で指定されたスコープに基づき、アプリからのアカウントへのアクセス要求を承認するようユーザーに求めます。その後、ユーザーは指定されたREDIRECT_URI
にリダイレクトされます。scope パラメータは、ユーザーに関連付けられたスコープのスペース区切りのリストです。た と えば、scope=read_user+profile
はread_user
とprofile
のスコープを要求します。リダイレクトには、例えば、作成者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&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にリクエストできるようになります。
作成者コードの流れ
作成者コードのフローは、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
このページでは、
REQUESTED_SCOPES
で指定されたスコープに基づき、アプリからのアカウントへのアクセス要求を承認するようユーザーに求めます。その後、ユーザーは指定されたREDIRECT_URI
にリダイレクトされます。scope パラメータは、ユーザーに関連付けられたスコープのスペース区切りのリストです。た と えば、scope=read_user+profile
はread_user
とprofile
のスコープを要求します。リダイレクトには、例えば、作成者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にリクエストできるようになります。
リソースオーナーのパスワード認証フロー
このフローでは、リソースオーナーの認証情報 (ユーザー名とパスワード) と引き換えにトークンが要求されます。
このクレデンシャルは、以下の場合にのみ使用します:
- リソースオーナーとクライアントの間に高度な信頼関係がある場合。例えば、クライアントがデバイスオペレーティングシステムの一部であったり、高度な特権を持つアプリケーションである場合。
- 他の権限付与タイプは使用できません(権限コードなど)。
このグラントタイプでは、クライアントがリソースオーナーのクレデンシャルに直接アクセスする必要がありますが、 リソースオーナーのクレデンシャルは 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.token
を使って GitLab API にアクセスします。access token
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 credential helperを使って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
フィールドはレスポンスに含まれます。
これらのフィールドはそれぞれscope
とexpires_in
のエイリアスであり、doorkeeper 5.0.2で導入された変更を破壊しないために含まれています。
これらのフィールドは後のリリースで削除される予定なので、当てにしないでください。
トークンの取り消し
トークンを失効させるには、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 レジストリへのさまざまな程度のアクセスをサポートしています:
- ユーザー認証を許可しない
- GitLabコンテナのレジストリ。
- GitLabPackage レジストリに登録されているパッケージ。
- コンテナレジストリ API を使ってユーザーがレジストリを取得、リストアップ、削除できるようにしました。