Retrieving, using and validating token from an IdentityServer

retrieving,-using-and-validating-token-from-an-identityserver

📮 Contact 🇧🇷 🇺🇸 🇫🇷

Twitter
LinkedIn

This is an example of how to a client application retrieves a token from a Identity Server and use it in an WebApi to consumes an endpoint.

How this project was created

This example was built based on Duende documentation

Identity Server

Identity provider for our sample.

Install Duende templates

dotnet new --install Duende.IdentityServer.Templates

Create an empty solution

dotnet new sln -n IdentityServerDemo

Create Identity server project

dotnet new isempty -n IdentityServer

Add IdendityServer projet to the blank solution

dotnet sln add .IdentityServerIdentityServer.csproj

Add scope to config.cs

public static IEnumerable<ApiScope> ApiScopes =>
    new ApiScope[]
        { new ApiScope(name: "campelo-api", displayName: "CampeloAPI") };

Add client to config.cs

public static IEnumerable<Client> Clients =>
    new Client[]
        { new Client
        {
            ClientId = "client",
            // no interactive user, use the clientid/secret for authentication
            AllowedGrantTypes = GrantTypes.ClientCredentials,
            // secret for authentication
            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },
            // scopes that client has access to
            AllowedScopes = { "campelo-api" }
        } };

Openid-configuration

Now you can access openid-configuration from the identity server. Run the solution and go to https://localhost:5001/.well-known/openid-configuration. So you can retrieve something like this.

{
   "issuer":"https://localhost:5001",
   "jwks_uri":"https://localhost:5001/.well-known/openid-configuration/jwks",
   "authorization_endpoint":"https://localhost:5001/connect/authorize",
   "token_endpoint":"https://localhost:5001/connect/token",
   "userinfo_endpoint":"https://localhost:5001/connect/userinfo",
   "end_session_endpoint":"https://localhost:5001/connect/endsession",
   "check_session_iframe":"https://localhost:5001/connect/checksession",
   "revocation_endpoint":"https://localhost:5001/connect/revocation",
   "introspection_endpoint":"https://localhost:5001/connect/introspect",
   "device_authorization_endpoint":"https://localhost:5001/connect/deviceauthorization",
   "backchannel_authentication_endpoint":"https://localhost:5001/connect/ciba",
   "frontchannel_logout_supported":true,
   "frontchannel_logout_session_supported":true,
   "backchannel_logout_supported":true,
   "backchannel_logout_session_supported":true,
   "scopes_supported":[
      "openid",
      "campelo-api",
      "offline_access"
   ],
   "claims_supported":[
      "sub"
   ],
   "grant_types_supported":[
      "authorization_code",
      "client_credentials",
      "refresh_token",
      "implicit",
      "urn:ietf:params:oauth:grant-type:device_code",
      "urn:openid:params:grant-type:ciba"
   ],
   "response_types_supported":[
      "code",
      "token",
      "id_token",
      "id_token token",
      "code id_token",
      "code token",
      "code id_token token"
   ],
   "response_modes_supported":[
      "form_post",
      "query",
      "fragment"
   ],
   "token_endpoint_auth_methods_supported":[
      "client_secret_basic",
      "client_secret_post"
   ],
   "id_token_signing_alg_values_supported":[
      "RS256"
   ],
   "subject_types_supported":[
      "public"
   ],
   "code_challenge_methods_supported":[
      "plain",
      "S256"
   ],
   "request_parameter_supported":true,
   "request_object_signing_alg_values_supported":[
      "RS256",
      "RS384",
      "RS512",
      "PS256",
      "PS384",
      "PS512",
      "ES256",
      "ES384",
      "ES512",
      "HS256",
      "HS384",
      "HS512"
   ],
   "authorization_response_iss_parameter_supported":true,
   "backchannel_token_delivery_modes_supported":[
      "poll"
   ],
   "backchannel_user_code_parameter_supported":true
}

API project

Web API project.

Create a new web API project

dotnet new webapi -n WebApi

Adding webapi to the solution

dotnet sln add .WebApiWebApi.csproj

Adding JWT Bearer authentication

dotnet add .WebApiWebApi.csproj package Microsoft.AspNetCore.Authentication.JwtBearer

Set JWT Bearer as the default authentication scheme

Update the Program.cs or Startup.cs file.

builder.Services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.Authority = "https://localhost:5001";

        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateAudience = false
        };
    });

/// UseAuthentication right before UseAuthorization
app.UseAuthentication();
app.UseAuthorization();

Add a new controller for testing

[Route("identity")]
[Authorize]
public class IdentityController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
    }
}

Configure the WebAPI to listen on Port 6001

Edit the launchSettings.json file in Properties folder.

"applicationUrl": "https://localhost:6001"

Run the WebAPI project

Now you have a 401 (unauthorized) error response when trying to access https://localhost:6001/identity

Client project

Create a console client project

dotnet new console -n Client

Add the client project to the solution

dotnet sln add .ClientClient.csproj

Add IdentityModel to the client project

dotnet add .ClientClient.csproj package IdentityModel

Discover endpoints from metadata

var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("https://localhost:5001");
if (disco.IsError)
{
    Console.WriteLine(disco.Error);
    return;
}

Request token

var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
    Address = disco.TokenEndpoint,

    ClientId = "client",
    ClientSecret = "secret",
    Scope = "campelo-api"
});

if (tokenResponse.IsError)
{
    Console.WriteLine(tokenResponse.Error);
    return;
}

Console.WriteLine(tokenResponse.AccessToken);

Call WebAPI

var apiClient = new HttpClient();
apiClient.SetBearerToken(tokenResponse.AccessToken);

var response = await apiClient.GetAsync("https://localhost:6001/identity");
if (!response.IsSuccessStatusCode)
{
    Console.WriteLine(response.StatusCode);
}
else
{
    var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync()).RootElement;
    Console.WriteLine(JsonSerializer.Serialize(doc, new JsonSerializerOptions { WriteIndented = true }));
}

Run client

Be sure that the IdentityServer and WebAPI are running and run the Client project to see something like this
Image 1

Source code

Source code

Typos or suggestions?

If you’ve found a typo, a sentence that could be improved or anything else that should be updated on this blog post, you can access it through a git repository and make a pull request. If you feel comfortable with github, instead of posting a comment, please go directly to https://github.com/campelo/documentation and open a new pull request with your changes.

Total
0
Shares
Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post
the-b2b-saas-sales-funnel:-how-your-brand-can-optimize-it-to-boost-conversions

The B2B SaaS Sales Funnel: How Your Brand Can Optimize It to Boost Conversions

Next Post
top-7-featured-dev-posts-from-the-past-week

Top 7 Featured DEV Posts from the Past Week

Related Posts

「設計ミス」の社会を再編する:AIと共創する未来の働き方とシステム思考

こんにちは、Soraです。この記事をお読みいただき、ありがとうございます。突然ですが、少しだけ想像してみてください。朝、もう少しだけ布団の温もりを感じていたいのに、「仕事だから」と自分にムチを打って起き上がる。満員電車に身体を押し込まれ、会社に着けば成果を求められ、同僚のフォローに追われる。気づけば形式だけの会議が続き、帰宅する頃には自分のための時間はほとんど残っていない…。もし、こうした日々に少しでも心当たりがあるなら、ふと胸の奥で「このままで、本当にいいのだろうか?」という静かな声が聞こえることがあるのではないでしょうか。本稿では、その胸のざわめきを「個人の怠け」や「甘え」として片付けるのではなく、私たちを取り巻く社会そのものの「設計ミス」のシグナルとして捉え直すことを提案します。そして、その設計をどうすれば再編できるのか、具体的なデータも交えながら、皆さんと一緒に考えていきたいと思います。### 第一章|「労働=価値」という虚構の検証私たちはいつの間にか、「働くことが人間の価値を決める」という前提を内面化しています。しかし、この考え方は本当に自明なのでしょうか。いくつかのデータは、この前提が現代において大きな歪みを生んでいる可能性を示唆しています。 **異常に低い仕事への熱意:米ギャラップ社の調査によると、日本の「熱意あふれる社員」の割合はわずか5%。これは調査した139カ国中、最下位レベルです。多くの人が、仕事に対してポジティブな感情を持てずにいる現状が伺えます。* 構造的な高ストレス状態:厚生労働省の調査では、仕事で強いストレスを感じている労働者の割合は、常に半数を超えています。これは個人の精神的な強さの問題ではなく、労働環境そのものに構造的な問題が潜んでいることの現れです。* 先進国で低位の労働生産性:日本の時間当たり労働生産性は、OECD加盟38カ国中30位(2022年)と、長年低い水準にあります。長時間働き、高いストレスを感じているにもかかわらず、それが必ずしも高い成果に結びついていないのです。これらの事実は、「個人の努力が足りない」からではなく、「努力の方向性を規定する社会の設計そのもの」に無理が生じていることを示しているのではないでしょうか。### 第二章|人生を“準備期間”にしてしまうプログラム私たちの多くは、無意識のうちに次のような人生のレールに乗せられています。 **学生時代:より良い大学に入るための「準備」* 大学時代:より良い会社に入るための「準備」* 社会人時代:昇進や老後のための「準備」* 老後:人生の終わりを迎えるための「準備」人生が常に何かの「準備」の連続で、「今、この瞬間を生きる」ことが後回しにされてしまう。この構造を支えているのが、「安定こそが正義」「みんなと同じが安心」といった、思考停止を促す“プログラム”です。このプログラムは、私たちの感性を少しずつ麻痺させ、構造への疑問を抱かせないように作用します。**### 第三章|思考のOSを更新する「言語の再設計」社会のプログラムから抜け出し、自分自身の思考を取り戻す第一歩は、言葉を意識的に変えることです。固定観念を強化する言葉を、私は「毒語」と呼んでいます。この毒語を、本質を捉えた「対抗語彙」に置き換えることで、世界の見え方は大きく変わります。| 毒語(思考停止を招く言葉) | 対抗語彙(本質を捉える言葉) | 置き換えの狙い || :—…
Read More