Extension Grants

OAuth 2.0はpassword、authorization_codeとのようなトークンエンドポイントの標準認可タイプを定義しますrefresh_token。拡張機能グラントは、トークンの変換、委任、カスタム資格などの非標準トークン発行シナリオのサポートを追加する方法です。

IExtensionGrantValidatorインタフェースを実装することによって、追加の許可タイプのサポートを追加することができます:

public interface IExtensionGrantValidator
{
    /// <summary>
    /// Handles the custom grant request.
    /// </summary>
    /// <param name="request">The validation context.</param>
    Task ValidateAsync(ExtensionGrantValidationContext context);

    /// <summary>
    /// Returns the grant type this validator can deal with
    /// </summary>
    /// <value>
    /// The type of the grant.
    /// </value>
    string GrantType { get; }
}

ExtensionGrantValidationContextオブジェクトは、あなたがにアクセスすることができます:

  • 受信トークン要求(よく知られている検証済みの値)とカスタム値(Rawコレクションを介したもの)
  • 結果 - エラーまたは成功
  • カスタム応答パラメータ

拡張グラントを登録するには、DIに追加します。

builder.AddExtensionGrantValidator<MyExtensionsGrantValidator>();

例:拡張認可を使用する単純な委任

次のシナリオを想像してみましょう。フロントエンドクライアントは、インタラクティブなフロー(例えば、ハイブリッドフロー)で取得したトークンを使用して中間層のAPIを呼び出します。この中間層API(API 1)は、対話ユーザーの代わりにバックエンドAPI(API 2)を呼び出す必要があります。

../_images/delegation.png

言い換えると、中間層API(API 1)には、ユーザーの識別情報を含むアクセストークンが必要ですが、バックエンドAPI(API 2)のスコープが必要です。

注釈

フロントエンドからのアクセストークンが単純にバックエンドに転送される、貧しい人の代表団という用語について聞いたことがあります。これにはいくつかの欠点があります。たとえば、API 2がAPI 1スコープを受け入れなければならないため、ユーザーはAPI 2を直接呼び出すことができます。また、トークンにデリゲート固有のクレームをいくつか追加することもできます。たとえば、コールパスがAPI 1経由であるという事実です。

拡張機能の実装

フロントエンドはトークンをAPI 1に送信し、このトークンをIdentityServerでAPI 2の新しいトークンと交換する必要があります。

有線では、交換機のトークンサービスへのコールは次のようになります。

POST /connect/token

grant_type=delegation&
scope=api2&
token=...&
client_id=api1.client
client_secret=secret

着信トークンを検証し、新しいトークンを表す結果を返すことによってその要求を処理するのは、拡張グラントバリデータの仕事です。

public class DelegationGrantValidator : IExtensionGrantValidator
{
    private readonly ITokenValidator _validator;

    public DelegationGrantValidator(ITokenValidator validator)
    {
        _validator = validator;
    }

    public string GrantType => "delegation";

    public async Task ValidateAsync(ExtensionGrantValidationContext context)
    {
        var userToken = context.Request.Raw.Get("token");

        if (string.IsNullOrEmpty(userToken))
        {
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
            return;
        }

        var result = await _validator.ValidateAccessTokenAsync(userToken);
        if (result.IsError)
        {
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
            return;
        }

        // get user's identity
        var sub = result.Claims.FirstOrDefault(c => c.Type == "sub").Value;

        context.Result = new GrantValidationResult(sub, GrantType);
        return;
    }
}

DIにバリデーターを登録することを忘れないでください。

委任クライアントの登録

IdentityServerにクライアント登録が必要です。これにより、クライアントは次のような新しい拡張機能を使用できます。

var client = new client
{
    ClientId = "api1.client",
    ClientSecrets = new List<Secret>
    {
        new Secret("secret".Sha256())
    },

    AllowedGrantTypes = { "delegation" },

    AllowedScopes = new List<string>
    {
        "api2"
    }
}

トークンエンドポイントの呼び出し

API 1では、HTTPペイロードを自分で作成することも、IdentityModelヘルパーライブラリを使用することもできます。

public async Task<TokenResponse> DelegateAsync(string userToken)
{
    var payload = new
    {
        token = userToken
    };

    // create token client
    var client = new TokenClient(disco.TokenEndpoint, "api1.client", "secret");

    // send custom grant to token endpoint, return response
    return await client.RequestCustomGrantAsync("delegation", "api2", payload);
}

これでTokenResponse.AccessToken、委任アクセストークンが含まれます。