Azure DevOps OAuth 2.0 を使用して Web アプリを作成する

Azure DevOps Services

重要

この情報は、既存の Azure DevOps OAuth アプリのみを対象としています。 新しいアプリ開発者は、Microsoft Entra ID OAuth を使用して Azure DevOps と統合する必要があります。

Azure DevOps は、OAuth 2.0 アプリの ID プロバイダーです。 OAuth 2.0 の実装により、開発者はユーザーのアプリを承認し、Azure DevOps リソースのアクセス トークンを取得できます。

Azure DevOps OAuth の概要

1. アプリを登録する

  1. アプリの登録に https://app.vsaex.visualstudio.com/app/register 移動します。

  2. アプリケーションに必要なスコープを選択し、アプリを承認するときに同じスコープを使用します。 プレビュー API を使用してアプリを登録した場合は、使用したスコープが非推奨になったため、再登録します。

  3. アプリケーションの作成を選択します。

    アプリケーション設定ページが表示されます。

    Screenshot showing Applications settings for your app.

    • Azure DevOps Services は、承認承認ページをユーザーに提示するときに、会社名、アプリ名、説明を使用します。 また、会社の Web サイト、アプリ Web サイト、サービス利用規約とプライバシーに関する声明の URL も使用します。

      Screenshot showing Visual Studio Codespaces authorization page with your company and app information.

    • Azure DevOps Services がユーザーの承認を要求し、ユーザーがそれを許可すると、ユーザーのブラウザーは承認コードを含む承認コールバック URL にリダイレクトされます。 コールバック URL は、コードをアプリに転送し、アプリに登録されている URL と正確に一致するセキュリティで保護された接続 (https) である必要があります。 そうでない場合は、アプリに承認を付与するようにユーザーに求めるページではなく、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}
パラメーター Notes
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=88e2dd5f-4e34-45c6-a75d-524eb2a0399e
        &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 要求ヘッダー - アプリを承認する

表題 Value
コンテンツタイプ 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}: クエリ パラメーターを介して code コールバック URL に指定された 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 ヘッダーにベアラー トークンとして含めます。

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 要求ヘッダー - 更新トークン

表題 Value
コンテンツタイプ 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 }
}

重要

ユーザーに対して新しい更新トークンが発行されます。 この新しいトークンを保持し、次回ユーザーの新しいアクセス トークンを取得する必要がある場合に使用します。

サンプル

OAuth を実装して Azure DevOps Services REST API を呼び出す C# サンプルは、C# OAuth GitHub サンプルにあります

クライアント シークレットを再生成する

5 年ごとに、アプリケーション シークレットの有効期限が切れます。 引き続きアクセス トークンと更新トークンを作成して使用できるように、アプリ シークレットを再生成する必要があります。 これを行うには、[シークレットの再生成] ボタンをクリックすると、この操作を完了することを確認するダイアログがポップアップ表示されます。

Screenshot confirming secret regeneration.

再生成することを確認すると、以前のアプリ シークレットは機能しなくなり、このシークレットで作成された以前のすべてのトークンも機能しなくなります。 顧客のダウンタイムを最小限に抑えるために、このクライアント シークレットのローテーションを十分に行ってください。

よく寄せられる質問 (FAQ)

Q: 携帯電話アプリで OAuth を使用できますか?

A: いいえ。 Azure DevOps Services は Web サーバー フローのみをサポートしているため、アプリ シークレットを安全に格納できないため、OAuth を実装する方法はありません。

Q: コードで処理する必要があるエラーや特別な条件は何ですか?

A: 次の条件を処理していることを確認します。

  • ユーザーがアプリのアクセスを拒否した場合、承認コードは返されません。 拒否をチェックせずに承認コードを使用しないでください。
  • ユーザーがアプリの承認を取り消した場合、アクセス トークンは無効になります。 アプリがトークンを使用してデータにアクセスすると、401 エラーが返されます。 もう一度承認を要求します。

Q: Web アプリをローカルでデバッグする必要があります。 アプリを登録するときにコールバック URL に localhost を使用できますか?

A:はい。 Azure DevOps Services では、コールバック URL で localhost が許可されるようになりました。 アプリを登録するときに、コールバック URL の先頭として使用 https://localhost してください。

Q: アクセス トークンを取得しようとすると、HTTP 400 エラーが発生します。 何が間違っている可能性がありますか?

A: 要求ヘッダーでコンテンツ タイプを application/x-www-form-urlencoded に設定していることを確認します。

Q: OAuth ベースのアクセス トークンを使用すると HTTP 401 エラーが発生しますが、スコープが同じ PAT でも問題ありません。 なぜですか?

A: OAuth 経由のサード パーティ製アプリケーション アクセスが、組織の管理者https://dev.azure.com/{your-org-name}/_settings/organizationPolicyによって無効になっていないことを確認します。 このシナリオでは、アプリを承認し、アクセス トークンを生成するフローが機能しますが、すべての REST API は、次のようなエラーのみを返します TF400813: The user "<GUID>" is not authorized to access this resource.

Q: SOAP エンドポイントと REST API で OAuth を使用できますか。

A: いいえ。 OAuth は、この時点で REST API でのみサポートされます。

Q: Azure DevOps REST API を使用して作業項目の添付ファイルの詳細を取得するにはどうすればよいですか?

A: 最初に、作業項目を使用して作業項目の詳細を 取得する - 作業項目 REST API を取得します。

GET https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/{id}

添付ファイルの詳細を取得するには、URL に次のパラメーターを追加する必要があります。

$expand=all

結果を使用して、relations プロパティを取得します。 そこに添付ファイルの URL があり、URL 内で ID を見つけることができます。 次に例を示します。

$url = https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/434?$expand=all&api-version=5.0

$workItem = Invoke-RestMethod -Uri $url -Method Get -ContentType application/json

$split = ($workitem.relations.url).Split('/')

$attachmentId = $split[$split.count - 1]

# Result: 1244nhsfs-ff3f-25gg-j64t-fahs23vfs