如何將一個 ASP.NET Core 網站快速加入 LINE Login 功能 (OpenID Connect) | The Will Will Web

The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何將一個 ASP.NET Core 網站快速加入 LINE Login 功能 (OpenID Connect)

前幾天原本想用 ASP.NET Core 寫一個最簡單的 LINE Login 範例程式出來,結果想不到這麼簡單的功能,卡關了兩天才找出解決之道。如果單純的透過 OAuth 2.0 授權流程來取得 Access Token 與 ID Token 其實還蠻簡單的。但是若希望可以做到 OpenID Connect 流程中自動透過 JWK (RFC 7517: JSON Web Key) 來驗證 Token 的有效性,這時可以直接使用 ASP.NET Core 內建的 Microsoft.AspNetCore.Authentication.OpenIdConnect 套件來完成。不過當方便的套件遇到特殊的實作時,那麼就是一場災難啦。這篇文章我打算來說說這次的踩雷之旅!

先來體驗一下使用 OpenID Connect 整合 Google 登入的過程

這個過程真的簡單到爆炸,不用上我的精通 OAuth 2.0 授權框架課程也能輕鬆整合 Google 提供的 OpenID Connect + OAuth 2.0 流程,以下是整個實作的過程:

  1. 建立一個全新的 ASP.NET Core MVC 專案

    dotnet new mvc -n GoogleLoginOIDCDemo
    cd GoogleLoginOIDCDemo
    dotnet new gitignore
    git init
    git add .
    git commit -m "Initial commit"
    
  2. 加入 Microsoft.AspNetCore.Authentication.OpenIdConnect 套件

    dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect
    
  3. 修改 Properties\launchSettings.json

    .profiles.GoogleLoginOIDCDemo.applicationUrl 的內容修改為 https://localhost:9001

  4. Google Developers ConsoleCredentials 註冊一個 OAuth 2.0 Client IDs

    取得 Client IDClient secret 之後,請務必設定 Authorized redirect URIs 並加入 https://localhost:9001/signin-oidc 網址!

    請到 appsettings.json 加入以下組態設定:

    "OpenIDConnect": {
      "Authority": "https://accounts.google.com",
      "ClientId": "<Your Client Id>",
      "ClientSecret": "<Your Client secret>"
    },
    
  5. Program.cs 加入 AddAuthentication 設定

    builder.Services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
        {
            options.Authority = builder.Configuration["OpenIDConnect:Authority"];
            options.ClientId = builder.Configuration["OpenIDConnect:ClientId"];
            options.ClientSecret = builder.Configuration["OpenIDConnect:ClientSecret"];
            options.ResponseType = "code";
    
            options.Scope.Add("openid");
            options.Scope.Add("profile");
    
            options.SaveTokens = true;
        });
    
  6. Program.cs 加入身份認證相關的 Middleware 設定

    app.UseAuthentication(); // <-- 加入這行
    app.UseAuthorization();
    
    app.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}")
        .RequireAuthorization(); // <-- 加入這行,這會讓整個網站都需要登入才能用!
    

恭喜你!只要上述六個步驟,網站就可以輕鬆整合 Google 帳號登入,幾乎可以說是無腦開發,也不用真的去注意什麼技術細節! 😎

如果你想要顯示一些 Claims 資訊,可以修改 Views\Home\Privacy.cshtml 檔案:

@using Microsoft.AspNetCore.Authentication
@{
    ViewData["Title"] = "Privacy Policy";
    var UserId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
    var UserName = @User.FindFirst(System.Security.Claims.ClaimTypes.Name)?.Value;
}

<h2>Hello @UserName (@UserId)</h2>
<img src="@(User.FindFirst("picture")?.Value)">


<h2>Claims</h2>

<dl>
    @foreach (var claim in User.Claims)
    {
        <dt>@claim.Type</dt>
        <dd>@claim.Value</dd>
    }
</dl>

<h2>Properties</h2>

<dl>
    @{
        var items = (await Context.AuthenticateAsync()).Properties?.Items;
    }
    @if (items != null) foreach (var prop in items)
    {
        <dt>@prop.Key</dt>
        <dd>@prop.Value</dd>
    }
</dl>

你也可以實作登出功能 (/Home/Logout),在登出時將 Cookies 清空即可:

using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using GoogleLoginOIDCDemo.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;

namespace GoogleLoginOIDCDemo.Controllers;

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }

    [AllowAnonymous]
    public IActionResult Index()
    {
        return View();
    }

    public IActionResult Privacy()
    {
        return View();
    }

    [AllowAnonymous]
    public async Task<IActionResult> Logout()
    {
        await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        return RedirectToAction(nameof(Index));
    }

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()
    {
        return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }
}

體驗一下使用 OpenID Connect 整合 LINE 登入的過程

以下步驟基本上與上述完全相同,只有步驟 4 與步驟 5 不一樣而已,感謝 OpenID Connect 提供業界標準規格,讓我們現在可以輕鬆的整合各家 IdP 登入!

  1. 建立一個全新的 ASP.NET Core MVC 專案

    dotnet new mvc -n LINELoginOIDCDemo
    cd LINELoginOIDCDemo
    dotnet new gitignore
    git init
    git add .
    git commit -m "Initial commit"
    
  2. 加入 Microsoft.AspNetCore.Authentication.OpenIdConnect 套件

    dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect
    
  3. 修改 Properties\launchSettings.json

    .profiles.GoogleLoginOIDCDemo.applicationUrl 的內容修改為 https://localhost:9001

  4. 到 [LINE Developers](LINE Developers) 新增一個 LINE Login 頻道 (Channel)

    取得 Channel IDChannel secret 之後,請務必設定 Authorized redirect URIs 並加入 https://localhost:9001/signin-oidc 網址!

    請到 appsettings.json 加入以下組態設定:

    "OpenIDConnect": {
      "Authority": "https://access.line.me",
      "ClientId": "<Your Client Id>",
      "ClientSecret": "<Your Client secret>"
    },
    
  5. Program.cs 加入 AddAuthentication 設定

    builder.Services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
        {
            options.Authority = builder.Configuration["OpenIDConnect:Authority"];
            options.ClientId = builder.Configuration["OpenIDConnect:ClientId"];
            options.ClientSecret = builder.Configuration["OpenIDConnect:ClientSecret"];
            options.ResponseType = "code";
    
            options.Scope.Add("openid");
            options.Scope.Add("profile");
    
            // LINE Login 不加入以下這一段設定,將無法走完 OpenID Connect 整個流程,最後會驗不過 JWT Token! 🔥
            options.Events = new OpenIdConnectEvents()
            {
                OnAuthorizationCodeReceived = context => {
                    context.TokenEndpointRequest?.SetParameter("id_token_key_type", "JWK");
                    return Task.CompletedTask;
                }
            };
    
            options.SaveTokens = true;
        });
    
  6. Program.cs 加入身份認證相關的 Middleware 設定

    app.UseAuthentication(); // <-- 加入這行
    app.UseAuthorization();
    
    app.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}")
        .RequireAuthorization(); // <-- 加入這行,這會讓整個網站都需要登入才能用!
    

不要看我文章寫的雲淡風清,我可是搞了兩天才終於找到 LINE Login 無法介接 OpenID Connect 流程的主要原因!

分析 LINE Login 無法使用 OpenID Connect 的原因

上一段的步驟 5 我特別加上了一個 options.Events 設定,你可以嘗試把這段 Code 移除,然後重新執行一次看看!

// options.Events = new OpenIdConnectEvents()
// {
//     OnAuthorizationCodeReceived	 = context => {
//         context.TokenEndpointRequest.SetParameter("id_token_key_type", "JWK");
//         return Task.CompletedTask;
//     }
// };

你在登入的過程,將會遇到一個 SecurityTokenSignatureKeyNotFoundException 例外狀況,完整訊息是:

SecurityTokenSignatureKeyNotFoundException: IDX10503: Signature validation failed. Token does not have a kid. Keys tried: 'System.Text.StringBuilder'.
Exceptions caught: 'System.Text.StringBuilder'.
token: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'.

    System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(string token, TokenValidationParameters validationParameters)

Exception: An error was encountered while handling the remote login.

    Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler<TOptions>.HandleRequestAsync()

從這段訊息,你可能猜到可能跟 ValidateSignature 有關,也就是說這個問題在驗證 JWT 簽章的時候出了問題,但為什麼出問題卻完全沒有頭緒。

由於現今個資意識抬頭,微軟在「個資保護」上也做出了許多貢獻,尤其是在 ASP.NET Core 開發框架中已經加入了許多個資保護措施,所有錯誤紀錄在輸出的時候,若判斷出可能潛藏 PII (Personally Identifiable Information) (個人識別資訊) 的訊息,預設就會加以隱藏。不過,隱藏了過多的訊息將會影響開發人員除錯,因此也有地方可以讓你設定顯示完整的 PII 資訊!

我為了要看到真正詳細的錯誤,必須加入以下設定:

if (builder.Environment.IsDevelopment())
{
    Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
}

加入設定之後,錯誤訊息就非常可怕了,資訊量極大,而且還真的有「敏感資料」在內,也就是 OpenID Connect 在登入的過程中取得的 ID Token 資訊,裡面有個資,重要的資料我會隱藏部分資訊:

Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10503: Signature validation failed. Token does not have a kid. Keys tried: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '26cf395f48162e4a377339b9520c706729e1fdc3a645b7a9ae77ac2a4875a808', InternalId: 'zQO7-nK5qSjPCceN4RLe5lbAF-pMFo4gCz9ycazRAkQ'. , KeyId: 26cf395f48162e4a377339b9520c706729e1fdc3a645b7a9ae77ac2a4875a808
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'e6a6919386169ba54de9dd336b41479a01012dc0c428baae2de18e59ee2146db', InternalId: 'lGMhdZBbHzz_zQoxIUWvkSl0KIz_mVHcKBnsYr3TXC0'. , KeyId: e6a6919386169ba54de9dd336b41479a01012dc0c428baae2de18e59ee2146db
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'a2a459aec5b65fa4e8add5c7697c79be445ae312bbcd6eef8fe09b5bb826cf3d', InternalId: 'JngdfT4xp1JZg6COCVDTconTCWEZCEsnXp6r8GjuVIw'. , KeyId: a2a459aec5b65fa4e8add5c7697c79be445ae312bbcd6eef8fe09b5bb826cf3d
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'ccd58c2f2646f45fe0b4bbb0237d62f0dd7bb1669d40c121b8488f10bf363900', InternalId: 'DTKuVm7Z2y15msDgZUNlfF3kD-OTjIoxtGqVMPhzUr8'. , KeyId: ccd58c2f2646f45fe0b4bbb0237d62f0dd7bb1669d40c121b8488f10bf363900
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '6aa8ad07cd2aaadcc656f7e2139cce8b8c4a6c81c29042f481680672fd03c969', InternalId: '45rSzGDC13EdOZZT_KXQdy63Tf5Pr9NvkV-NOqSBelk'. , KeyId: 6aa8ad07cd2aaadcc656f7e2139cce8b8c4a6c81c29042f481680672fd03c969
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '95e9119f653eae095bb3d871d6ba8ff46467aa314575a4543615f051d4b735a6', InternalId: 'hJY8tS5Epxmk8T4vRKfq_KpKT0h4Bq4qLR91lc9GPng'. , KeyId: 95e9119f653eae095bb3d871d6ba8ff46467aa314575a4543615f051d4b735a6
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'fa134042993a4a1717e4ee16b0c48f354de6171f850155971885038288fb92c9', InternalId: 'thHNSwUT7dt0od2rM8U675_UafX9-7L7Lg3iioTWVKs'. , KeyId: fa134042993a4a1717e4ee16b0c48f354de6171f850155971885038288fb92c9
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '5cee37e69c353766a3fe01fa05bf821283541a84a6692cdeddf947d0c0904367', InternalId: 'Cu9y564ReaVcZ23MGEmnPXhyBCY0rVqa2lo0nwqQBcc'. , KeyId: 5cee37e69c353766a3fe01fa05bf821283541a84a6692cdeddf947d0c0904367
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '0f7ac0f8a22e131b5fe75a9ce1699aca150f7f6c0ed75e282b3bf7fb097a763e', InternalId: 'BH1sUBvnQBoJBxzuf1gGgYZtxbSTUd-5aFBbdx5gjtc'. , KeyId: 0f7ac0f8a22e131b5fe75a9ce1699aca150f7f6c0ed75e282b3bf7fb097a763e
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '7f31159a65aa4bf1ddf342b57170dd7467e92d12e84c24ca20e1442553b3f08c', InternalId: 'upVHbhSUmmarKaGVgKeL3_eHY1mt-Wg-CGw1h3toQy4'. , KeyId: 7f31159a65aa4bf1ddf342b57170dd7467e92d12e84c24ca20e1442553b3f08c
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'a7968c2ea15f0f41635de5e088290491b0231a56a49cc8a6cd6ed441727a252f', InternalId: 'MncTWIwixQ8JKaCNVPFdQSi_8H7On3OszZ_C8LYH52I'. , KeyId: a7968c2ea15f0f41635de5e088290491b0231a56a49cc8a6cd6ed441727a252f
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '9b1112b098f3184c6e83fc3d1be8fc217db1eb20756a156cb63ce8ce9e27dfd2', InternalId: '7yu2XJJuODs6oQ18N3ouQoFEq51wxSQ-Iei0gFt2m_Y'. , KeyId: 9b1112b098f3184c6e83fc3d1be8fc217db1eb20756a156cb63ce8ce9e27dfd2
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'fe1e8d888ec664cd2afef479c5db79692cd01aacd141483a54339351f395fa27', InternalId: 'Db9ulGmfQ-cpLAFAww0hdDV1zYnxvDCohdxH5JlJQBk'. , KeyId: fe1e8d888ec664cd2afef479c5db79692cd01aacd141483a54339351f395fa27
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '8cce8f074ed02378fa80705644812a2672ed7751f5b9069893557734f21bf728', InternalId: '3U5xTi9-d_x6vuE9F47QDTsc8Zu95T1a0IWEtxoY5Ns'. , KeyId: 8cce8f074ed02378fa80705644812a2672ed7751f5b9069893557734f21bf728
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '9291e6b6a38c7d8af68c5266faa28208d6dd59845faa024e541bdb39fe135d4b', InternalId: 'JNpsMvn6bx-a28YIEQNGEbq5iuYrevovYtuG_qqPCaM'. , KeyId: 9291e6b6a38c7d8af68c5266faa28208d6dd59845faa024e541bdb39fe135d4b
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '7159e3eae0f7f2d868f3c09b6de930ec3363ec04526f40caec9b1f08e0f43ca6', InternalId: 'MJPYgDQTYKlWZUfo7_qCtHjvagNko7D2jxyhvAHGkP4'. , KeyId: 7159e3eae0f7f2d868f3c09b6de930ec3363ec04526f40caec9b1f08e0f43ca6
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '1f067eec599b74bf4e28c243c7fba6463a035933553e31f7a388e14d44fa48e3', InternalId: 'WOAx0WuMzQsFQGFOeBaurwNdnbZcOVioA4IBRO0zODA'. , KeyId: 1f067eec599b74bf4e28c243c7fba6463a035933553e31f7a388e14d44fa48e3
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'a524a404e7a97d35dc64633756305525ed2dc4a5b48a130736f74e9a3a5d4b1d', InternalId: 'e8j49FESBt3TKvfot1SHAzpHx9Z8_ZnhO3KNA0NUa9A'. , KeyId: a524a404e7a97d35dc64633756305525ed2dc4a5b48a130736f74e9a3a5d4b1d
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'a2fd5181692cc6daf799905d0dcd7b0826b458c9fe794b9056fc7b4db61cfba4', InternalId: 'V8XewU-dlOdK3wS52OjX1RANkBhUogbTT2djEPjqY6I'. , KeyId: a2fd5181692cc6daf799905d0dcd7b0826b458c9fe794b9056fc7b4db61cfba4
Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'c6f34e863d3e5e32ba32081402d8b3e10e8edb638568a57b2716c0f30f567103', InternalId: '6zSiYCnmlAMCcCCEVVCgyxbnEbpdRTX_qWgaThxsPmo'. , KeyId: c6f34e863d3e5e32ba32081402d8b3e10e8edb638568a57b2716c0f30f567103
'.
Exceptions caught:
 'System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '26cf395f48162e4a377339b9520c706729e1fdc3a645b7a9ae77ac2a4875a808', InternalId: 'zQO7-nK5qSjPCceN4RLe5lbAF-pMFo4gCz9ycazRAkQ'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'e6a6919386169ba54de9dd336b41479a01012dc0c428baae2de18e59ee2146db', InternalId: 'lGMhdZBbHzz_zQoxIUWvkSl0KIz_mVHcKBnsYr3TXC0'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'a2a459aec5b65fa4e8add5c7697c79be445ae312bbcd6eef8fe09b5bb826cf3d', InternalId: 'JngdfT4xp1JZg6COCVDTconTCWEZCEsnXp6r8GjuVIw'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'ccd58c2f2646f45fe0b4bbb0237d62f0dd7bb1669d40c121b8488f10bf363900', InternalId: 'DTKuVm7Z2y15msDgZUNlfF3kD-OTjIoxtGqVMPhzUr8'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '6aa8ad07cd2aaadcc656f7e2139cce8b8c4a6c81c29042f481680672fd03c969', InternalId: '45rSzGDC13EdOZZT_KXQdy63Tf5Pr9NvkV-NOqSBelk'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '95e9119f653eae095bb3d871d6ba8ff46467aa314575a4543615f051d4b735a6', InternalId: 'hJY8tS5Epxmk8T4vRKfq_KpKT0h4Bq4qLR91lc9GPng'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'fa134042993a4a1717e4ee16b0c48f354de6171f850155971885038288fb92c9', InternalId: 'thHNSwUT7dt0od2rM8U675_UafX9-7L7Lg3iioTWVKs'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '5cee37e69c353766a3fe01fa05bf821283541a84a6692cdeddf947d0c0904367', InternalId: 'Cu9y564ReaVcZ23MGEmnPXhyBCY0rVqa2lo0nwqQBcc'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '0f7ac0f8a22e131b5fe75a9ce1699aca150f7f6c0ed75e282b3bf7fb097a763e', InternalId: 'BH1sUBvnQBoJBxzuf1gGgYZtxbSTUd-5aFBbdx5gjtc'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '7f31159a65aa4bf1ddf342b57170dd7467e92d12e84c24ca20e1442553b3f08c', InternalId: 'upVHbhSUmmarKaGVgKeL3_eHY1mt-Wg-CGw1h3toQy4'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'a7968c2ea15f0f41635de5e088290491b0231a56a49cc8a6cd6ed441727a252f', InternalId: 'MncTWIwixQ8JKaCNVPFdQSi_8H7On3OszZ_C8LYH52I'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '9b1112b098f3184c6e83fc3d1be8fc217db1eb20756a156cb63ce8ce9e27dfd2', InternalId: '7yu2XJJuODs6oQ18N3ouQoFEq51wxSQ-Iei0gFt2m_Y'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'fe1e8d888ec664cd2afef479c5db79692cd01aacd141483a54339351f395fa27', InternalId: 'Db9ulGmfQ-cpLAFAww0hdDV1zYnxvDCohdxH5JlJQBk'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '8cce8f074ed02378fa80705644812a2672ed7751f5b9069893557734f21bf728', InternalId: '3U5xTi9-d_x6vuE9F47QDTsc8Zu95T1a0IWEtxoY5Ns'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '9291e6b6a38c7d8af68c5266faa28208d6dd59845faa024e541bdb39fe135d4b', InternalId: 'JNpsMvn6bx-a28YIEQNGEbq5iuYrevovYtuG_qqPCaM'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '7159e3eae0f7f2d868f3c09b6de930ec3363ec04526f40caec9b1f08e0f43ca6', InternalId: 'MJPYgDQTYKlWZUfo7_qCtHjvagNko7D2jxyhvAHGkP4'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: '1f067eec599b74bf4e28c243c7fba6463a035933553e31f7a388e14d44fa48e3', InternalId: 'WOAx0WuMzQsFQGFOeBaurwNdnbZcOVioA4IBRO0zODA'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'a524a404e7a97d35dc64633756305525ed2dc4a5b48a130736f74e9a3a5d4b1d', InternalId: 'e8j49FESBt3TKvfot1SHAzpHx9Z8_ZnhO3KNA0NUa9A'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'a2fd5181692cc6daf799905d0dcd7b0826b458c9fe794b9056fc7b4db61cfba4', InternalId: 'V8XewU-dlOdK3wS52OjX1RANkBhUogbTT2djEPjqY6I'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'c6f34e863d3e5e32ba32081402d8b3e10e8edb638568a57b2716c0f30f567103', InternalId: '6zSiYCnmlAMCcCCEVVCgyxbnEbpdRTX_qWgaThxsPmo'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
'.
token: '{"typ":"JWT","alg":"HS256"}.{"iss":"https://access.line.me","sub":"U4e4149f4c49.....d73fe53","aud":"1657038220","exp":1649356921,"iat":1649353321,"nonce":"637849501190374595.....","amr":["linesso"],"name":"Will","picture":"https://profile.line-scdn.net/0hq3-UwB3ELhwQ...."}'.
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.ValidateToken(String idToken, AuthenticationProperties properties, TokenValidationParameters validationParameters, JwtSecurityToken& jwt)
   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleRemoteAuthenticateAsync()

這段龐雜的訊息中,我可以看出 3 個重點:

  1. ASP.NET Core 嘗試了一堆「金鑰」,但就是找不到,因此出現 SecurityTokenSignatureKeyNotFoundException 例外。

    Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10503: Signature validation failed. Token does not have a kid. Keys tried: (這裡嘗試了十多把金鑰都不對)
    
  2. 錯誤訊息中提到 IDX10634: Unable to create the SignatureProvider 這個問題:

    System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
    Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.ECDsaSecurityKey, KeyId: 'c6f34e863d3e5e32ba32081402d8b3e10e8edb638568a57b2716c0f30f567103', InternalId: '6zSiYCnmlAMCcCCEVVCgyxbnEbpdRTX_qWgaThxsPmo'. is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
    

    這段錯誤訊息有個網址,列出了所有該套件支援的加密演算法清單(Supported Algorithms),我認真看了一下,該套件支援的演算法非常多,業界知名的老早就都有支援了,不太可能是這個問題。

    由於 ASP.NET Core Authentication 相關套件的原始碼放在 AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet 專案下,所以你可以從這裡找到許多有用的資訊,尤其是Microsoft.IdentityModel 相關原始碼

  3. 訊息最後有列出從呼叫 Token Endpoint 的 ID Token 的完整內容

    token: '{"typ":"JWT","alg":"HS256"}.{"iss":"https://access.line.me","sub":"U4e4149f4c49.....d73fe53","aud":"1657038220","exp":1649356921,"iat":1649353321,"nonce":"637849501190374595.....","amr":["linesso"],"name":"Will","picture":"https://profile.line-scdn.net/0hq3-UwB3ELhwQ...."}'.
    

    這裡最詭異的地方就是 "alg":"HS256" 這裡了,因為我從 LINE Login 的 OpenID Configuration 頁面可以看到 jwks_uri 的網址在 https://api.line.me/oauth2/v2.1/certs,而這裡的 JWK 金鑰清單中,清一色都是採用 ES256 演算法,這也意味著 LINE Login 所簽發出來的 JWT Token 是有問題的。

也因為我花了一整個晚上,搞到半夜才最終確診應該是 LINE Login 本身設計的瑕疵所致。之後就是漫長又枯燥的研究過程,第一步當然是先看看官方文件有沒有什麼蛛絲馬跡,結果沒有,啥都找不到,瞎子摸象真的難受,但我就是不信邪,一定要找出問題!

後來經另一位 LAE (LINE API Expert) 提醒,他說透過 LIFF 可以取得以 ES256 演算法簽發出來的 ID Token,因此我也嘗試了一下,發現還真的是這樣。想說這也太詭異了吧,我完全走標準的 OAuth 2.0 流程取得的 Token 怎麼會有完全不同的結果呢?!

這時我真的要說,如果你不瞭解 OAuth 2.0 授權協議的過程,也不清楚 OpenID Connect 的運作原理,要透過有限的錯誤訊息找出真相,那真的是比登天還難。這也是為什麼我花了大量時間設計這套《精通 OAuth 2.0 授權框架》課程的主要原因!🔥

我們用 OpenID Connect 登入,為了取得 Access Token 與 ID Token,過程中走的一定是 OAuth 2.0 授權流程,這些都是標準,不太可能有什麼差錯。我們先透過 Authorization Endpoint 登入與授權,然後再去 Token Endpoint 取得 Access Token 與 ID Token,這些都沒問題。有問題的地方,以我過往的經驗,通常都是各家 IdP (Identity Provider) 有時候會實作自己的擴充邏輯,偶爾加上一些參數之類的屢見不鮮。但你要知道,當我們使用一個別人寫好現成的套件,通常就會過度依賴套件帶來的簡便性,理論上大部分的 IdP 應該都很好介接,但就是偶爾會出現幾家超級難接的,你只懂得套件的基本用法,基本上就會卡關的很慘很慘。像我這次遇到的問題,就是在 Google 完全找不到類似的的討論,也沒有範例程式可以參考,最終還是要回歸 OAuth 與 OIDC 協議本身,從根本解決問題。

這個問題我如何解決的呢?我最後是跑去看 LIFF v2 的 JavaScript SDK 原始碼 (https://static.line-scdn.net/liff/edge/2/sdk.js),而且這份是 Minify (壓縮) 過的原始碼,基於對 OAuth 2.0 的理解,我直接在檔案中搜尋 authorization_code 這個關鍵字,果然給我找到 LIFF v2 在取得 ID Token 時的關鍵邏輯,參數如下:

image

原來 LIFF SDK 在呼叫 Token Endpoint 取得 Token 的時候,額外送出了一個自訂的 id_token_key_type 參數,其值還必須設定為 JWK 才行,這是 LINE 自己擴充的行為,並非標準的一部份。我喜出望外的先用 Postman 如法炮製一番,果然成功取得以 ES256 演算法簽發的 JWT Token,這實在是太讓人歡心雀躍啦! 😄

找到 Root Cause (問題的根源) 之後,就只要找出 ASP.NET Core Authentication 要如何修改這個呼叫 Token Endpoint 的過程,並加以調整即可。還好 Microsoft.AspNetCore.Authentication.OpenIdConnect 套件真的做的超棒,幾乎 OAuth 2.0 / OpenID Connect 整個流程的任何一個環節都有留下事件(OpenIdConnectEvents)可以讓你客製化調整,不過這部分的文件依然相當欠缺,還是要靠理解與消化才能找到你需要的寫法。在理解 OAuth 2.0 授權協議的前提下,我終於找出短短的幾行設定,加上之後所有問題就都解決啦! 👍

這段 Code 的重點在第 4 行的 context.TokenEndpointRequest.SetParameter("id_token_key_type", "JWK"); 這段,他可以在讓你呼叫 Token Endpoint 的時候,額外加上一個 id_token_key_type 參數:

options.Events = new OpenIdConnectEvents()
{
    OnAuthorizationCodeReceived	= context => {
        context.TokenEndpointRequest.SetParameter("id_token_key_type", "JWK");
        return Task.CompletedTask;
    }
};

後記

老實說,研究 OAuth 2.0 + OpenID Connect + JWK + Cryptography Model 這些主題每個都很大,如果再早個兩年,我大概沒有能力可以解開這個迷團。我大可在遇到問題的當下,直接用以下程式碼跳過 JWT 簽章檢查,這段 Code 是可以從 StackOverflow 找到的「唯一」解決方案,但是卻會讓應用程式暴露於風險之中,所以我才不計成本,額外花了兩天找出最完整、最安全的解決方案!

.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    // ...

    options.TokenValidationParameters = new TokenValidationParameters()
    {
        SignatureValidator = delegate(string token, TokenValidationParameters parameters)
        {
            return JwtSecurityToken(token);
        }
    };

});

其實我在 Review 公司內執行的專案時,也偶爾會看到一些似是而非的解法,很多時候我真的會不計成本,花上大量的時間去研究出正確的解法,而且通常都有不錯的成果。不過,有時也真的會礙於專案時程上的限制,不得以先推出一個應變措施(Workaround),這是沒辦法的辦法,這種事也是業界常態,在你妥協的當下,技術債、安全債就已經形成,如果不即時處理,日後肯定還是要還債的!😅

相關連結