diff --git a/authorization-dotnet/DecodeJwt/App/App.csproj b/authorization-dotnet/DecodeJwt/App/App.csproj
index bb496081c7..ac8d17ed1d 100644
--- a/authorization-dotnet/DecodeJwt/App/App.csproj
+++ b/authorization-dotnet/DecodeJwt/App/App.csproj
@@ -2,13 +2,13 @@
Exe
- net8.0
+ net10.0
enable
enable
-
-
+
+
diff --git a/authorization-dotnet/DecodeJwt/App/JwtUtils.cs b/authorization-dotnet/DecodeJwt/App/JwtUtils.cs
index c7174aa835..d0b70f0540 100644
--- a/authorization-dotnet/DecodeJwt/App/JwtUtils.cs
+++ b/authorization-dotnet/DecodeJwt/App/JwtUtils.cs
@@ -1,5 +1,7 @@
-using System.IdentityModel.Tokens.Jwt;
-using IdentityModel.Client;
+using System.Buffers.Text;
+using System.Text;
+using Duende.IdentityModel.Client;
+using Microsoft.IdentityModel.JsonWebTokens;
namespace App;
@@ -20,25 +22,25 @@ public static class JwtUtils
{ Address = discoveryDocument.TokenEndpoint, ClientId = "m2m", ClientSecret = "secret", Scope = "api" });
}
- if (tokenResponse.IsError)
+ if (tokenResponse.IsError)
{
throw new Exception(tokenResponse.Error);
}
-
+
return tokenResponse.AccessToken;
}
- public static JwtSecurityToken ConvertJwtStringToJwtSecurityToken(string? jwt)
+ public static JsonWebToken ConvertJwtStringToJsonWebToken(string jwt)
{
- var handler = new JwtSecurityTokenHandler();
- var token = handler.ReadJwtToken(jwt);
-
+ var handler = new JsonWebTokenHandler();
+ var token = handler.ReadJsonWebToken(jwt);
+
return token;
}
- public static DecodedToken DecodeJwt(JwtSecurityToken token)
+ public static DecodedToken DecodeJwt(JsonWebToken token)
{
- var keyId = token.Header.Kid;
+ var keyId = token.Kid;
var audience = token.Audiences.ToList();
var claims = token.Claims.Select(claim => (claim.Type, claim.Value)).ToList();
@@ -48,12 +50,21 @@ public static DecodedToken DecodeJwt(JwtSecurityToken token)
audience,
claims,
token.ValidTo,
- token.SignatureAlgorithm,
- token.RawData,
+ token.Alg,
+ token.EncodedToken,
token.Subject,
token.ValidFrom,
token.EncodedHeader,
token.EncodedPayload
);
}
+
+ public static (string Header, string Payload) DecodeJwtWithoutLibrary(string jwt)
+ {
+ var parts = jwt.Split('.');
+ var header = Encoding.UTF8.GetString(Base64Url.DecodeFromChars(parts[0]));
+ var payload = Encoding.UTF8.GetString(Base64Url.DecodeFromChars(parts[1]));
+
+ return (header, payload);
+ }
}
diff --git a/authorization-dotnet/DecodeJwt/App/Program.cs b/authorization-dotnet/DecodeJwt/App/Program.cs
index 350180ffd1..f9a75b3bfa 100644
--- a/authorization-dotnet/DecodeJwt/App/Program.cs
+++ b/authorization-dotnet/DecodeJwt/App/Program.cs
@@ -1,8 +1,12 @@
using App;
-var accessToken = await JwtUtils.GetAccessTokenFromDuendeIdentityServerAsync();
+var accessToken = await JwtUtils.GetAccessTokenFromDuendeIdentityServerAsync()
+ ?? throw new InvalidOperationException("The token endpoint returned no access token.");
Console.WriteLine(accessToken);
-var jwt = JwtUtils.ConvertJwtStringToJwtSecurityToken(accessToken);
+var jwt = JwtUtils.ConvertJwtStringToJsonWebToken(accessToken);
Console.WriteLine(jwt);
var jwtData = JwtUtils.DecodeJwt(jwt);
Console.WriteLine(jwtData);
+var (header, payload) = JwtUtils.DecodeJwtWithoutLibrary(accessToken);
+Console.WriteLine(header);
+Console.WriteLine(payload);
diff --git a/authorization-dotnet/DecodeJwt/Tests/DecodeJwtTest.cs b/authorization-dotnet/DecodeJwt/Tests/DecodeJwtTest.cs
index be826fd12f..5845f24081 100644
--- a/authorization-dotnet/DecodeJwt/Tests/DecodeJwtTest.cs
+++ b/authorization-dotnet/DecodeJwt/Tests/DecodeJwtTest.cs
@@ -3,7 +3,7 @@ namespace Tests;
public class DecodeJwtTest
{
[Fact]
- public async Task WhenJwtIsRetrievedFromServer_ThenItShouldNotBeNull()
+ public async Task WhenJwtIsRetrievedFromServer_ThenItShouldNotBeNull_Live()
{
var jwt = await JwtUtils.GetAccessTokenFromDuendeIdentityServerAsync();
@@ -14,11 +14,21 @@ public async Task WhenJwtIsRetrievedFromServer_ThenItShouldNotBeNull()
[ClassData(typeof(JwtTestData))]
public void WhenJwtIsValid_ThenItShouldDecode(string token)
{
- var jwt = JwtUtils.ConvertJwtStringToJwtSecurityToken(token);
+ var jwt = JwtUtils.ConvertJwtStringToJsonWebToken(token);
var jwtData = JwtUtils.DecodeJwt(jwt);
Assert.NotNull(jwtData.Issuer);
Assert.NotEmpty(jwtData.Audience);
Assert.NotEmpty(jwtData.Claims);
}
-}
\ No newline at end of file
+
+ [Theory]
+ [ClassData(typeof(JwtTestData))]
+ public void WhenJwtIsDecodedWithoutLibrary_ThenHeaderAndPayloadAreJson(string token)
+ {
+ var (header, payload) = JwtUtils.DecodeJwtWithoutLibrary(token);
+
+ Assert.Contains("\"alg\":\"RS256\"", header);
+ Assert.Contains("\"iss\":\"https://demo.duendesoftware.com\"", payload);
+ }
+}
diff --git a/authorization-dotnet/DecodeJwt/Tests/Tests.csproj b/authorization-dotnet/DecodeJwt/Tests/Tests.csproj
index 5884ed7ca2..c878fa5b95 100644
--- a/authorization-dotnet/DecodeJwt/Tests/Tests.csproj
+++ b/authorization-dotnet/DecodeJwt/Tests/Tests.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net10.0
enable
enable
@@ -10,13 +10,13 @@
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all