Skip to content

Commit 8deef46

Browse files
authored
Merge pull request #191 from marcominerva/copilot/make-jwtbearerservice-public
Make JwtBearerService public with virtual methods for extensibility
2 parents b5654b7 + 11332d3 commit 8deef46

File tree

1 file changed

+33
-23
lines changed

1 file changed

+33
-23
lines changed

src/SimpleAuthentication/JwtBearer/JwtBearerService.cs

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,35 @@
66

77
namespace SimpleAuthentication.JwtBearer;
88

9-
internal class JwtBearerService(IOptions<JwtBearerSettings> jwtBearerSettingsOptions) : IJwtBearerService
9+
/// <summary>
10+
/// Default implementation of <see cref="IJwtBearerService"/> that provides JWT Bearer token generation and validation.
11+
/// </summary>
12+
/// <param name="jwtBearerSettingsOptions">The JWT Bearer settings.</param>
13+
public class JwtBearerService(IOptions<JwtBearerSettings> jwtBearerSettingsOptions) : IJwtBearerService
1014
{
11-
private readonly JwtBearerSettings jwtBearerSettings = jwtBearerSettingsOptions.Value;
15+
/// <summary>
16+
/// Gets the JWT Bearer settings used by this service.
17+
/// </summary>
18+
protected JwtBearerSettings JwtBearerSettings { get; } = jwtBearerSettingsOptions.Value;
1219

13-
public Task<string> CreateTokenAsync(string userName, IList<Claim>? claims = null, string? issuer = null, string? audience = null, DateTime? absoluteExpiration = null)
20+
/// <inheritdoc />
21+
public virtual Task<string> CreateTokenAsync(string userName, IList<Claim>? claims = null, string? issuer = null, string? audience = null, DateTime? absoluteExpiration = null)
1422
{
1523
claims ??= [];
16-
claims.Update(jwtBearerSettings.NameClaimType, userName);
24+
claims.Update(JwtBearerSettings.NameClaimType, userName);
1725
claims.Update(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString());
1826

1927
var now = DateTime.UtcNow;
2028

2129
var securityTokenDescriptor = new SecurityTokenDescriptor()
2230
{
23-
Subject = new ClaimsIdentity(claims, jwtBearerSettings.SchemeName, jwtBearerSettings.NameClaimType, jwtBearerSettings.RoleClaimType),
24-
Issuer = issuer ?? jwtBearerSettings.Issuers?.FirstOrDefault(),
25-
Audience = audience ?? jwtBearerSettings.Audiences?.FirstOrDefault(),
31+
Subject = new ClaimsIdentity(claims, JwtBearerSettings.SchemeName, JwtBearerSettings.NameClaimType, JwtBearerSettings.RoleClaimType),
32+
Issuer = issuer ?? JwtBearerSettings.Issuers?.FirstOrDefault(),
33+
Audience = audience ?? JwtBearerSettings.Audiences?.FirstOrDefault(),
2634
IssuedAt = now,
27-
NotBefore = now.Add(-jwtBearerSettings.ClockSkew),
28-
Expires = absoluteExpiration ?? (jwtBearerSettings.ExpirationTime.GetValueOrDefault() > TimeSpan.Zero ? now.Add(jwtBearerSettings.ExpirationTime!.Value) : DateTime.MaxValue),
29-
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtBearerSettings.SecurityKey)), jwtBearerSettings.Algorithm)
35+
NotBefore = now.Add(-JwtBearerSettings.ClockSkew),
36+
Expires = absoluteExpiration ?? (JwtBearerSettings.ExpirationTime.GetValueOrDefault() > TimeSpan.Zero ? now.Add(JwtBearerSettings.ExpirationTime!.Value) : DateTime.MaxValue),
37+
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtBearerSettings.SecurityKey)), JwtBearerSettings.Algorithm)
3038
};
3139

3240
var tokenHandler = new JsonWebTokenHandler();
@@ -35,7 +43,8 @@ public Task<string> CreateTokenAsync(string userName, IList<Claim>? claims = nul
3543
return Task.FromResult(token);
3644
}
3745

38-
public async Task<ClaimsPrincipal> ValidateTokenAsync(string token, bool validateLifetime = true)
46+
/// <inheritdoc />
47+
public virtual async Task<ClaimsPrincipal> ValidateTokenAsync(string token, bool validateLifetime = true)
3948
{
4049
var tokenHandler = new JsonWebTokenHandler();
4150

@@ -46,23 +55,23 @@ public async Task<ClaimsPrincipal> ValidateTokenAsync(string token, bool validat
4655

4756
var tokenValidationParameters = new TokenValidationParameters
4857
{
49-
AuthenticationType = jwtBearerSettings.SchemeName,
50-
NameClaimType = jwtBearerSettings.NameClaimType,
51-
RoleClaimType = jwtBearerSettings.RoleClaimType,
52-
ValidateIssuer = jwtBearerSettings.Issuers?.Any() ?? false,
53-
ValidIssuers = jwtBearerSettings.Issuers,
54-
ValidateAudience = jwtBearerSettings.Audiences?.Any() ?? false,
55-
ValidAudiences = jwtBearerSettings.Audiences,
58+
AuthenticationType = JwtBearerSettings.SchemeName,
59+
NameClaimType = JwtBearerSettings.NameClaimType,
60+
RoleClaimType = JwtBearerSettings.RoleClaimType,
61+
ValidateIssuer = JwtBearerSettings.Issuers?.Any() ?? false,
62+
ValidIssuers = JwtBearerSettings.Issuers,
63+
ValidateAudience = JwtBearerSettings.Audiences?.Any() ?? false,
64+
ValidAudiences = JwtBearerSettings.Audiences,
5665
ValidateIssuerSigningKey = true,
57-
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtBearerSettings.SecurityKey)),
66+
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtBearerSettings.SecurityKey)),
5867
RequireExpirationTime = true,
5968
ValidateLifetime = validateLifetime,
60-
ClockSkew = jwtBearerSettings.ClockSkew
69+
ClockSkew = JwtBearerSettings.ClockSkew
6170
};
6271

6372
var validationResult = await tokenHandler.ValidateTokenAsync(token, tokenValidationParameters);
6473

65-
if (!validationResult.IsValid || validationResult.SecurityToken is not JsonWebToken jsonWebToken || jsonWebToken.Alg != jwtBearerSettings.Algorithm)
74+
if (!validationResult.IsValid || validationResult.SecurityToken is not JsonWebToken jsonWebToken || jsonWebToken.Alg != JwtBearerSettings.Algorithm)
6675
{
6776
throw new SecurityTokenException("Token is expired or invalid", validationResult.Exception);
6877
}
@@ -71,12 +80,13 @@ public async Task<ClaimsPrincipal> ValidateTokenAsync(string token, bool validat
7180
return principal;
7281
}
7382

74-
public async Task<string> RefreshTokenAsync(string token, bool validateLifetime, DateTime? absoluteExpiration = null)
83+
/// <inheritdoc />
84+
public virtual async Task<string> RefreshTokenAsync(string token, bool validateLifetime, DateTime? absoluteExpiration = null)
7585
{
7686
var principal = await ValidateTokenAsync(token, validateLifetime);
7787
var claims = (principal.Identity as ClaimsIdentity)!.Claims.ToList();
7888

79-
var userName = claims.First(c => c.Type == jwtBearerSettings.NameClaimType).Value;
89+
var userName = claims.First(c => c.Type == JwtBearerSettings.NameClaimType).Value;
8090
var issuer = claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Iss)?.Value;
8191
var audience = claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Aud)?.Value;
8292

0 commit comments

Comments
 (0)