极狐 GitLab

OAuth 2.0 身份识别提供商 API

Tier: 基础版, 专业版, 旗舰版

Offering: JihuLab.com, 私有化部署

使用此 API 允许第三方服务通过 OAuth 2.0 协议访问极狐GitLab 资源。更多信息,请参见配置极狐GitLab 作为 OAuth 2.0 身份验证提供者

跨域资源共享#

版本历史
  • 在极狐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 不建议使用此流程。
  • 设备授权授予 (极狐GitLab 17.1 及更高版本) 面向无浏览器访问的设备的安全流程。需要辅助设备完成授权流程。

OAuth 2.1 的草案规范特别省略了隐式授予和资源所有者密码凭证流程。

参考 OAuth RFC 了解所有这些流程的工作原理并选择适合您用例的流程。

授权代码(带或不带 PKCE)流程要求首先通过用户账户中的 /user_settings/applications 页面注册 application。在注册期间,通过启用适当的范围,您可以限制 application 可以访问的资源范围。创建后,您将获得 application 凭证:Application IDClient SecretClient Secret 必须保持安全。当您的应用程序架构允许时,保密 Application ID 也是有利的。

有关极狐GitLab 中范围的列表,请参见提供者文档

防止 CSRF 攻击#

要保护基于重定向的流程,OAuth 规范建议使用“一次性 CSRF 令牌,在每次请求时通过 state 参数安全绑定到用户代理”,与每次请求一起发送到 /oauth/authorize 端点。这可以防止 CSRF 攻击。

在生产环境中使用 HTTPS#

对于生产环境,请为您的 redirect_uri 使用 HTTPS。对于开发,极狐GitLab 允许不安全的 HTTP 重定向 URI。

由于 OAuth 2.0 完全基于传输层的安全性,因此您不应使用未保护的 URI。有关更多信息,请参见 OAuth 2.0 RFC 和 OAuth 2.0 威胁模型 RFC。

在以下部分中,您可以找到有关如何获取每个流程授权的详细说明。

带有 Proof Key for Code Exchange (PKCE) 的授权代码#

PKCE RFC 包含从授权请求到访问令牌的详细流程描述。以下步骤描述了我们对该流程的实现。

带有 PKCE 的授权代码流程,简称 PKCE,使得在公共客户端上安全执行 OAuth 客户端凭证交换为访问令牌成为可能,而无需访问 Client Secret。这使得 PKCE 流程对于单页面 JavaScript 应用程序或其他客户端应用程序来说是有利的,因为在这些应用程序中保持用户的密钥不被泄露是技术上不可能的。

在开始流程之前,生成 STATECODE_VERIFIERCODE_CHALLENGE

  • STATE 是一个不可预测的值,由客户端用于在请求和回调之间维持状态。它还应用作 CSRF 令牌。
  • CODE_VERIFIER 是一个长度在 43 到 128 个字符之间的随机字符串,使用字符 A-Za-z0-9-._~
  • CODE_CHALLENGECODE_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
  1. 请求授权代码。为此,您应将用户重定向到 /oauth/authorize 页面,并带有以下查询参数:

    plaintext
    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_URIscope 参数 是与用户关联的范围的空格分隔列表。例如,scope=read_user+profile 请求 read_userprofile 范围。重定向包括授权 code,例如:

    plaintext
    https://example.com/oauth/redirect?code=1234567890&state=STATE
  2. 使用从前一个请求中返回的授权 code(在以下示例中表示为 RETURNED_CODE),您可以使用任何 HTTP 客户端请求 access_token。以下示例使用 Ruby 的 rest-client

    ruby
    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

    示例响应:

    json
    1{ 2 "access_token": "de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54", 3 "token_type": "bearer", 4 "expires_in": 7200, 5 "refresh_token": "8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1", 6 "created_at": 1607635748 7}
  3. 要检索新的 access_token,请使用 refresh_token 参数。刷新令牌可在 access_token 本身过期后使用。此请求:

    • 使现有的 access_tokenrefresh_token 失效。
    • 在响应中发送新令牌。
    ruby
    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

    示例响应:

    json
    1{ 2 "access_token": "c97d1fe52119f38c7f67f0a14db68d60caa35ddc86fd12401718b649dcfa9c68", 3 "token_type": "bearer", 4 "expires_in": 7200, 5 "refresh_token": "803c1fd487fec35562c205dac93e9d8e08f9d3652a24079d704df3039df1158f", 6 "created_at": 1628711391 7}
`redirect_uri` 必须与原始授权请求中使用的 `redirect_uri` 匹配。

您现在可以使用访问令牌对 API 发起请求。

授权代码流程#

检查 RFC 规范以获取详细的流程描述。

授权代码流程与带有 PKCE 的授权代码流程基本相同。

在开始流程之前,生成 STATE。它是一个不可预测的值,由客户端用于在请求和回调之间维持状态。它还应用作 CSRF 令牌。

  1. 请求授权代码。为此,您应将用户重定向到 /oauth/authorize 页面,并带有以下查询参数:

    plaintext
    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_URIscope 参数 是与用户关联的范围的空格分隔列表。例如,scope=read_user+profile 请求 read_userprofile 范围。重定向包括授权 code,例如:

    plaintext
    https://example.com/oauth/redirect?code=1234567890&state=STATE
  2. 使用从前一个请求中返回的授权 code(在以下示例中表示为 RETURNED_CODE),您可以使用任何 HTTP 客户端请求 access_token。以下示例使用 Ruby 的 rest-client

    ruby
    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

    示例响应:

    json
    1{ 2 "access_token": "de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54", 3 "token_type": "bearer", 4 "expires_in": 7200, 5 "refresh_token": "8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1", 6 "created_at": 1607635748 7}
  3. 要检索新的 access_token,请使用 refresh_token 参数。刷新令牌可在 access_token 本身过期后使用。此请求:

    • 使现有的 access_tokenrefresh_token 失效。
    • 在响应中发送新令牌。
    ruby
    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

    示例响应:

    json
    1{ 2 "access_token": "c97d1fe52119f38c7f67f0a14db68d60caa35ddc86fd12401718b649dcfa9c68", 3 "token_type": "bearer", 4 "expires_in": 7200, 5 "refresh_token": "803c1fd487fec35562c205dac93e9d8e08f9d3652a24079d704df3039df1158f", 6 "created_at": 1628711391 7}
`redirect_uri` 必须与原始授权请求中使用的 `redirect_uri` 匹配。

您现在可以使用返回的访问令牌对 API 发起请求。

设备授权授予流程#

版本历史
  • 在极狐GitLab 17.2 中引入,使用名为 oauth2_device_grant_flow功能标志
  • 在 17.3 中默认启用。
  • 在极狐GitLab 17.9 中 GA。功能标志 oauth2_device_grant_flow 移除。
检查 RFC 规范以获取设备授权授予流程的详细描述,从设备授权请求到浏览器登录的令牌响应。

设备授权授予流程使得从没有浏览器交互选项的输入受限设备上安全地认证您的极狐GitLab 身份成为可能。

这使得设备授权授予流程对于尝试从无头服务器或其他没有或有限用户界面的设备上使用极狐GitLab 服务的用户来说是理想的选择。

  1. 要请求设备授权,输入受限设备客户端发送请求到 https://gitlab.example.com/oauth/authorize_device。例如:

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

    成功请求后,返回给用户一个包含 verification_uri 的响应。例如:

    json
    1{ 2 "device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS", 3 "user_code": "0A44L90H", 4 "verification_uri": "https://gitlab.example.com/oauth/device", 5 "verification_uri_complete": "https://gitlab.example.com/oauth/device?user_code=0A44L90H", 6 "expires_in": 300, 7 "interval": 5 8}
  2. 设备客户端向请求用户显示响应中的 user_codeverification_uri。该用户然后在具有浏览器访问权限的辅助设备上:

    1. 转到提供的 URI。
    2. 输入用户代码。
    3. 按提示完成身份验证。
  3. 在显示 verification_uriuser_code 之后,设备客户端立即开始使用初始响应中返回的关联 device_code 轮询令牌端点:

    ruby
    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 规范对于授权令牌。

    示例响应:

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

    收到此响应后,设备客户端继续轮询。

    如果轮询间隔太短,返回缓慢错误响应。例如:

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

    收到此响应后,设备客户端降低其轮询速率并以新的速率继续轮询。

    如果设备代码在身份验证完成之前过期,则返回过期令牌错误响应。例如:

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

    此时,设备客户端应停止并发起新的设备授权请求。

    如果授权请求被拒绝,返回访问被拒绝错误响应。例如:

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

    身份验证请求已被拒绝。用户应验证其凭据或联系其系统管理员

  5. 用户成功认证后,返回成功响应:

    json
    1{ 2 "access_token": "TOKEN", 3 "token_type": "Bearer", 4 "expires_in": 7200, 5 "scope": "read", 6 "created_at": 1593096829 7}

此时,设备认证流程已完成。返回的 access_token 可以提供给极狐GitLab 以在访问极狐GitLab 资源时认证用户身份,例如通过 HTTPS 克隆或访问 API。

可以在以下位置找到实现客户端设备流程的示例应用程序:https://gitlab.com/johnwparent/git-auth-over-https

资源所有者密码凭证流程#

检查 [RFC 规范](https://www.rfc-editor.org/rfc/rfc6749#section-4.3) 以获取详细的流程描述。
对于启用了 [双因素认证](../user/profile/account/two_factor_authentication.md) 的用户和[企业用户](../user/enterprise_user/_index.md),资源所有者密码凭证被禁用,这些用户的[群组禁用密码认证](../user/enterprise_user/_index.md#disable-password-authentication-for-enterprise-users)。这些用户可以使用[个人访问令牌](../user/profile/personal_access_tokens.md)访问 API。
确保为支持密码凭证流程的极狐GitLab 实例选择了 [**允许通过 HTTP(S) 进行 Git 的密码认证**](../administration/settings/sign_in_restrictions.md#password-authentication-enabled) 复选框。

在此流程中,请求令牌以换取资源所有者凭证(用户名和密码)。

凭证仅应在以下情况下使用:

  • 资源所有者与客户端之间的信任度很高。例如,客户端是设备操作系统的一部分或特权很高的应用程序。
  • 没有其他授权授予类型可用(如授权代码)。
切勿存储用户的凭据,仅在客户端部署到受信任环境时使用此授予类型,在 99% 的情况下,[个人访问令牌](../user/profile/personal_access_tokens.md) 是更好的选择。

即使此授予类型需要客户端直接访问资源所有者凭证,资源所有者凭证也仅用于单个请求,并交换为访问令牌。此授予类型可以通过将凭证与长效访问令牌或刷新令牌交换,来消除客户端存储资源所有者凭证以供将来使用的需要。

要请求访问令牌,您必须向 /oauth/token 发起一个 POST 请求,并带有以下参数:

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

示例 cURL 请求:

shell
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 应用程序通过 HTTP 基本认证与应用程序的 client_idclient_secret 使用此授予流程:

shell
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"

然后,您会收到一个包含访问令牌的响应:

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

默认情况下,访问令牌的范围是 api,它提供完全的读/写访问权限。

为了测试,您可以使用 oauth2 Ruby gem:

ruby
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 参数传递:

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

或者您可以将令牌放入 Authorization 头:

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

使用 access token 通过 HTTPS 访问 Git#

具有 scope read_repositorywrite_repository 的令牌可以通过 HTTPS 访问 Git。使用令牌作为密码。您可以将用户名设置为任何字符串值。您应该使用 oauth2

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

或者,您可以使用 Git 凭证助手 通过 OAuth 认证到极狐GitLab。这将自动处理 OAuth 令牌刷新。

检索令牌信息#

要验证令牌的详细信息,请使用 Doorkeeper gem 提供的 token/info 端点。

您必须提供访问令牌,可以是:

  • 作为参数:

    plaintext
    GET https://gitlab.example.com/oauth/token/info?access_token=<OAUTH-TOKEN>
  • 在 Authorization 头中:

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

以下是示例响应:

json
1{ 2 "resource_owner_id": 1, 3 "scope": ["api"], 4 "expires_in": null, 5 "application": {"uid": "1cb242f495280beb4291e64bee2a17f330902e499882fe8e1e2aa875519cab33"}, 6 "created_at": 1575890427 7}

已弃用字段#

响应中包含的字段 scopesexpires_in_seconds 已被弃用。字段 scopesscope 的别名,字段 expires_in_secondsexpires_in 的别名。

撤销令牌#

要撤销令牌,请使用 revoke 端点。API 返回 200 响应代码和一个空的 JSON 哈希以指示成功。

ruby
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 注册表的不同程度的访问,因为它们: