使用 Azure DevOps OAuth 2.0 创建 Web 应用

Azure DevOps Services

重要

Azure DevOps OAuth 定于 2026 年弃用。 此信息仅适用于现有的 Azure DevOps OAuth 应用。 若要创建新应用,请使用 Microsoft Entra ID OAuth 与 Azure DevOps 集成。 从 2025 年 2 月开始,我们将停止接受新的 Azure DevOps OAuth 应用。 在我们的博客文章中了解详细信息。

Azure DevOps 是 OAuth 2.0 应用的标识提供者。 OAuth 2.0 的实现可让开发人员为用户授权其应用,并获取 Azure DevOps 资源的访问令牌。

Azure DevOps OAuth 入门

1.注册应用

重要

从 2025 年 2 月开始,将阻止新应用创建。

  1. 转到 https://app.vsaex.visualstudio.com/app/register 注册应用。

  2. 选择应用程序所需的范围,然后在授权应用使用相同的范围。 如果使用预览 API 注册了应用,请重新注册,因为所使用的范围现已弃用。

  3. 选择创建应用程序

    将显示应用程序设置页。

    显示应用的应用程序设置的屏幕截图。

    • 当 Azure DevOps Services 向用户显示授权审批页时,它将使用公司名称、应用名称和说明。 它还使用公司网站、应用网站以及服务条款和隐私声明的 URL。

      显示包含公司和应用信息的 Visual Studio Codespaces 授权页的屏幕截图。

    • 当 Azure DevOps Services 要求用户授权,并且用户授予授权时,用户的浏览器会使用授权代码重定向到授权回调 URL。 回调 URL 必须是安全连接(https),才能将代码传输回应用,并且与应用中注册的 URL 完全匹配。 如果没有,则会显示 400 错误页,而不是要求用户向应用授予授权的页面。

  4. 如果想要让用户授权应用访问其组织,请调用授权 URL 并传递应用 ID 和授权范围。 若要获取访问令牌来调用 Azure DevOps Services REST API,请调用访问令牌 URL。

注册的每个应用的设置可从配置文件 https://app.vssps.visualstudio.com/profile/view获取。

2.授权应用

  1. 如果用户未授权应用访问其组织,请调用授权 URL。 如果用户批准授权,它会使用授权代码调用你。
https://app.vssps.visualstudio.com/oauth2/authorize
        ?client_id={app ID}
        &response_type={Assertion}
        &state={state}
        &scope={scope}
        &redirect_uri={callback URL}
参数 类型 备注
client_id GUID 注册应用时分配给应用的 ID。
response_type string Assertion
state string 可以是任何值。 通常,生成的字符串值将回调与其关联的授权请求相关联。
scope string 向应用注册的范围。 空格分隔。 请参阅 可用范围
redirect_uri URL 应用的回调 URL。 必须与注册到应用的 URL 完全匹配。
  1. 将用户转到 Azure DevOps Services 授权终结点的站点添加链接或按钮:
https://app.vssps.visualstudio.com/oauth2/authorize
        ?client_id=00001111-aaaa-2222-bbbb-3333cccc4444
        &response_type=Assertion
        &state=User1
        &scope=vso.work%20vso.code_write
        &redirect_uri=https://fabrikam.azurewebsites.net/myapp/oauth-callback

Azure DevOps Services 要求用户授权应用。

假设用户接受,Azure DevOps Services 会将用户的浏览器重定向到回调 URL,包括短期授权代码和授权 URL 中提供的状态值:

https://fabrikam.azurewebsites.net/myapp/oauth-callback
        ?code={authorization code}
        &state=User1

3.获取用户的访问权限和刷新令牌

使用授权代码为用户请求访问令牌(和刷新令牌)。 服务必须向 Azure DevOps Services 发出服务到服务 HTTP 请求。

URL - 授权应用

POST https://app.vssps.visualstudio.com/oauth2/token

HTTP 请求标头 - 授权应用

标头
Content-Type application/x-www-form-urlencoded
Content-Type: application/x-www-form-urlencoded

HTTP 请求正文 - 授权应用

client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion={0}&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={1}&redirect_uri={2}

替换上一示例请求正文中的占位符值:

  • {0}:注册应用时获取的 URL 编码客户端密码
  • {1}:通过查询参数提供给回调 URL 的 code URL 编码的“代码”
  • {2}:向应用注册的回调 URL

用于形成请求正文的 C# 示例 - 授权应用

public string GenerateRequestPostData(string appSecret, string authCode, string callbackUrl)
{
   return String.Format("client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion={0}&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={1}&redirect_uri={2}",
               HttpUtility.UrlEncode(appSecret),
               HttpUtility.UrlEncode(authCode),
               callbackUrl
        );
}

响应 - 授权应用

{
    "access_token": { access token for the user },
    "token_type": { type of token },
    "expires_in": { time in seconds that the token remains valid },
    "refresh_token": { refresh token to use to acquire a new access token }
}

注意

安全地保留 refresh_token ,以便应用无需提示用户再次授权。 访问令牌快速过期,不应持久保存。

4.使用访问令牌

若要使用访问令牌,请将其作为持有者令牌包含在 HTTP 请求的授权标头中:

Authorization: Bearer {access_token}

例如,用于获取项目最近生成的 HTTP 请求

GET https://dev.azure.com/myaccount/myproject/_apis/build-release/builds?api-version=3.0
Authorization: Bearer {access_token}

5.刷新过期的访问令牌

如果用户的访问令牌过期,可以使用他们在授权流中获取的刷新令牌来获取新的访问令牌。 就像交换访问和刷新令牌的授权代码的原始过程一样。

URL - 刷新令牌

POST https://app.vssps.visualstudio.com/oauth2/token

HTTP 请求标头 - 刷新令牌

标头
Content-type application/x-www-form-urlencoded
内容长度 请求正文的计算字符串长度(请参阅以下示例)
Content-Type: application/x-www-form-urlencoded
Content-Length: 1654

HTTP 请求正文 - 刷新令牌

client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion={0}&grant_type=refresh_token&assertion={1}&redirect_uri={2}

替换上一示例请求正文中的占位符值:

  • {0}:注册应用时获取的 URL 编码客户端密码
  • {1}:用户的 URL 编码刷新令牌
  • {2}:向应用注册的回调 URL

响应 - 刷新令牌

{
    "access_token": { access token for this user },
    "token_type": { type of token },
    "expires_in": { time in seconds that the token remains valid },
    "refresh_token": { new refresh token to use when the token has timed out }
}

注意

为用户颁发新的刷新令牌。 保留此新令牌,并在下次需要为用户获取新的访问令牌时使用它。

示例

可以在 C# OAuth GitHub 示例中找到实现 OAuth 以调用 Azure DevOps Services REST API 的 C# 示例

重新生成客户端密码

每五年一次,应用程序机密将过期。 重新生成应用机密以继续创建和使用访问令牌和刷新令牌。 为此,请选择“重新生成机密”,然后确认要完成此操作。

确认重新生成机密的屏幕截图。

确认要重新生成时,上一个应用机密不再有效,并且使用此机密模拟的所有以前的令牌也会停止工作。 请确保将此客户端机密轮换时间很好地缩短,以最大程度地减少任何客户停机时间。

删除应用

如果不再需要应用,请将其从配置文件中删除。

  1. 转到个人资料: https://app.vssps.visualstudio.com/profile/view.

  2. 通过从侧栏中名称下的下拉菜单中进行选择,确保位于正确的租户页面上。

  3. 在左侧边栏上的 “应用程序和服务 ”标头下查找应用。

  4. 在应用程序注册页上选择“删除”。 此时会显示一个模式,用于确认删除。

    应用元数据页的屏幕截图,其中突出显示了“删除”按钮

  5. 删除应用注册后,应用会中断,我们停止挖掘新令牌或接受此应用的模拟令牌。

常见问题 (FAQ)

问:是否可以将 OAuth 与手机应用配合使用?

答: 不是。 Azure DevOps Services 仅支持 Web 服务器流,因此无法实现 OAuth,因为无法安全地存储应用机密。

问:代码中需要处理哪些错误或特殊条件?

答:确保处理以下条件:

  • 如果用户拒绝应用访问,则不会返回授权代码。 请勿在不检查拒绝的情况下使用授权代码。
  • 如果用户撤销应用的授权,则访问令牌不再有效。 当应用使用令牌访问数据时,将返回 401 错误。 再次请求授权。

问:我想在本地调试 Web 应用。 注册应用时,是否可以将 localhost 用于回调 URL?

答:是的。 Azure DevOps Services 现在允许回调 URL 中的 localhost。 确保注册应用时用作 https://localhost 回调 URL 的开头。

问:尝试获取访问令牌时,我收到 HTTP 400 错误。 可能出了什么问题?

答:检查是否在请求标头中将内容类型设置为 application/x-www-form-urlencoded。

问:使用基于 OAuth 的访问令牌时,收到 HTTP 401 错误,但具有相同范围的 PAT 正常工作。 为什么?

答:验证组织的管理员是否未通过 OAuth 禁用https://dev.azure.com/{your-org-name}/_settings/organizationPolicy第三方应用程序访问。 在此方案中,授权应用并生成访问令牌的流有效,但所有 REST API 仅返回错误,例如 TF400813: The user "<GUID>" is not authorized to access this resource.