使用 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 月开始,将阻止新应用创建。
转到
https://app.vsaex.visualstudio.com/app/register
注册应用。选择应用程序所需的范围,然后在授权应用时使用相同的范围。 如果使用预览 API 注册了应用,请重新注册,因为所使用的范围现已弃用。
选择创建应用程序。
将显示应用程序设置页。
当 Azure DevOps Services 向用户显示授权审批页时,它将使用公司名称、应用名称和说明。 它还使用公司网站、应用网站以及服务条款和隐私声明的 URL。
当 Azure DevOps Services 要求用户授权,并且用户授予授权时,用户的浏览器会使用授权代码重定向到授权回调 URL。 回调 URL 必须是安全连接(https),才能将代码传输回应用,并且与应用中注册的 URL 完全匹配。 如果没有,则会显示 400 错误页,而不是要求用户向应用授予授权的页面。
如果想要让用户授权应用访问其组织,请调用授权 URL 并传递应用 ID 和授权范围。 若要获取访问令牌来调用 Azure DevOps Services REST API,请调用访问令牌 URL。
注册的每个应用的设置可从配置文件 https://app.vssps.visualstudio.com/profile/view
获取。
2.授权应用
- 如果用户未授权应用访问其组织,请调用授权 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 完全匹配。 |
- 将用户转到 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# 示例。
重新生成客户端密码
每五年一次,应用程序机密将过期。 重新生成应用机密以继续创建和使用访问令牌和刷新令牌。 为此,请选择“重新生成机密”,然后确认要完成此操作。
确认要重新生成时,上一个应用机密不再有效,并且使用此机密模拟的所有以前的令牌也会停止工作。 请确保将此客户端机密轮换时间很好地缩短,以最大程度地减少任何客户停机时间。
删除应用
如果不再需要应用,请将其从配置文件中删除。
转到个人资料:
https://app.vssps.visualstudio.com/profile/view
.通过从侧栏中名称下的下拉菜单中进行选择,确保位于正确的租户页面上。
在左侧边栏上的 “应用程序和服务 ”标头下查找应用。
在应用程序注册页上选择“删除”。 此时会显示一个模式,用于确认删除。
删除应用注册后,应用会中断,我们停止挖掘新令牌或接受此应用的模拟令牌。
常见问题 (FAQ)
问:是否可以将 OAuth 与手机应用配合使用?
答: 不是。 Azure DevOps Services 仅支持 Web 服务器流,因此无法实现 OAuth,因为无法安全地存储应用机密。
问:代码中需要处理哪些错误或特殊条件?
答:确保处理以下条件:
- 如果用户拒绝应用访问,则不会返回授权代码。 请勿在不检查拒绝的情况下使用授权代码。
- 如果用户撤销应用的授权,则访问令牌不再有效。 当应用使用令牌访问数据时,将返回 401 错误。 再次请求授权。
问:我想在本地调试 Web 应用。 注册应用时,是否可以将 localhost 用于回调 URL?
A:是的。 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.