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),這是沒辦法的辦法,這種事也是業界常態,在你妥協的當下,技術債、安全債就已經形成,如果不即時處理,日後肯定還是要還債的!😅

相關連結