Skip to content

Commit

Permalink
Add Audience on the refresh token
Browse files Browse the repository at this point in the history
  • Loading branch information
oveldman committed Feb 3, 2024
1 parent 5b04044 commit 8ba6d5c
Show file tree
Hide file tree
Showing 32 changed files with 561 additions and 55 deletions.
15 changes: 14 additions & 1 deletion MadWorld/MadWorld.Backend.API/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ private static void Main(string[] args)
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
ValidAudiences = builder.Configuration.GetSection("Jwt:Audiences").Get<string[]>(),
IssuerSigningKey =
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!))
};
Expand All @@ -75,6 +75,18 @@ private static void Main(string[] args)
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

const string madWorldOrigins = "_myAllowSpecificOrigins";
builder.Services.AddCors(options =>
{
options.AddPolicy(name: madWorldOrigins,
policy =>
{
policy.WithOrigins(builder.Configuration.GetSection("Cors:AllowedOrigins").Get<string[]>()!);
policy.AllowAnyMethod();
policy.AllowAnyHeader();
});
});

builder.Services.AddRateLimiter(rateLimiterOptions =>
{
Expand Down Expand Up @@ -107,6 +119,7 @@ private static void Main(string[] args)
app.AddTestEndpoints();

app.UseRateLimiter();
app.UseCors(madWorldOrigins);

app.MigrateDatabases();

Expand Down
21 changes: 19 additions & 2 deletions MadWorld/MadWorld.Backend.API/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,25 @@
},
"Jwt": {
"Key": "mSWX4ctFHyPAPYddRzgVETAUEj3oJE2cNCPfhbyW9K5M4rXYjR",
"Issuer": "https://identity.mad-world.nl/",
"Audience": "https://identity.mad-world.nl/"
"Issuer": "https://localhost:7056/",
"Audiences": [
"https://localhost:7298/",
"https://localhost:7177/",
"https://localhost:7056/",
"https://localhost:7180/",
"https://localhost:7205/",
"https://localhost:7300/"
]
},
"Cors": {
"AllowedOrigins": [
"https://localhost:7298",
"https://localhost:7177",
"https://localhost:7056",
"https://localhost:7180",
"https://localhost:7205",
"https://localhost:7300"
]
},
"Logging": {
"LogLevel": {
Expand Down
19 changes: 18 additions & 1 deletion MadWorld/MadWorld.Backend.API/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,24 @@
"Jwt": {
"Key": "Empty",
"Issuer": "https://identity.mad-world.nl/",
"Audience": "https://api.mad-world.nl/"
"Audiences": [
"https://admin.mad-world.nl/",
"https://api.mad-world.nl/",
"https://identity.mad-world.nl/",
"https://shipsimulator.mad-world.nl/",
"https://shipsimulator-api.mad-world.nl/",
"https://www.mad-world.nl/"
]
},
"Cors": {
"AllowedOrigins": [
"https://admin.mad-world.nl",
"https://api.mad-world.nl",
"https://identity.mad-world.nl",
"https://shipsimulator.mad-world.nl",
"https://shipsimulator-api.mad-world.nl",
"https://www.mad-world.nl"
]
},
"Logging": {
"LogLevel": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ namespace MadWorld.Backend.Identity.Contracts.UserManagers;
public class RefreshTokenContract
{
public string Id { get; set; }
public string Audience { get; set; }
public DateTime Expires { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public JwtGenerator(IConfiguration configuration)
_configuration = configuration;
}

public JwtToken GenerateToken(IdentityUserExtended user, IList<string> roles)
public JwtToken GenerateToken(IdentityUserExtended user, string audience, IList<string> roles)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_configuration["Jwt:Key"]!);
Expand All @@ -42,7 +42,7 @@ public JwtToken GenerateToken(IdentityUserExtended user, IList<string> roles)
Subject = new ClaimsIdentity(claims),
Expires = expires,
Issuer = _configuration["Jwt:Issuer"],
Audience = _configuration["Jwt:Audience"],
Audience = audience,
SigningCredentials =
new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ private static RefreshTokenContract ToRefreshTokenContract(RefreshToken refreshT
return new RefreshTokenContract()
{
Id = refreshToken.Id.ToString(),
Audience = refreshToken.Audience,
Expires = refreshToken.Expires
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public PostJwtLoginUseCase(IJwtGenerator jwtGenerator, IUserRepository userRepos
_userManager = userManager;
}

public async Task<IResult> PostJwtLogin(JwtLoginRequest request)
public async Task<IResult> PostJwtLogin(JwtLoginRequest request, string audience)
{
var result = await _signInManager.PasswordSignInAsync(request.Email, request.Password, false, false);
if (!result.Succeeded)
Expand All @@ -33,10 +33,10 @@ public async Task<IResult> PostJwtLogin(JwtLoginRequest request)
var user = await _userManager.FindByEmailAsync(request.Email);
var roles = await _userManager.GetRolesAsync(user!);

var jwt = _jwtGenerator.GenerateToken(user!, roles);
var jwt = _jwtGenerator.GenerateToken(user!, audience, roles);
var token = GenerateRefreshToken();

var refreshToken = new RefreshToken(token, expires: DateTime.UtcNow.AddDays(7), user!.Id);
var refreshToken = new RefreshToken(token, audience, expires: DateTime.UtcNow.AddDays(7), user!.Id);
await _userRepository.AddRefreshToken(refreshToken);

return Results.Ok(new JwtLoginResponse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public PostJwtRefreshUseCase(IJwtGenerator jwtGenerator, UserManager<IdentityUse
_userRepository = userRepository;
}

public async Task<IResult> PostJwtRefresh(JwtRefreshRequest request)
public async Task<IResult> PostJwtRefresh(JwtRefreshRequest request, string audience)
{
var refreshToken = _userRepository.GetRefreshToken(request.RefreshToken);

Expand All @@ -31,7 +31,7 @@ public async Task<IResult> PostJwtRefresh(JwtRefreshRequest request)
var user = refreshToken.User;
var roles = await _userManager.GetRolesAsync(user);

var jwt = _jwtGenerator.GenerateToken(user, roles);
var jwt = _jwtGenerator.GenerateToken(user, audience, roles);

return Results.Ok(new JwtRefreshResponse()
{
Expand Down
2 changes: 1 addition & 1 deletion MadWorld/MadWorld.Backend.Identity/Domain/IJwtGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ namespace MadWorld.Backend.Identity.Domain;

public interface IJwtGenerator
{
JwtToken GenerateToken(IdentityUserExtended user, IList<string> roles);
JwtToken GenerateToken(IdentityUserExtended user, string audience, IList<string> roles);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ public class RefreshToken
{
public const int MaxLength = 1000;

public RefreshToken(string token, DateTime expires, string userId)
public RefreshToken(string token, string audience, DateTime expires, string userId)
{
Token = token;
Audience = audience;
Expires = expires;
UserId = userId;
}
private RefreshToken() {}

public Guid Id { get; set; }
public string Audience { get; set; } = string.Empty;
public string Token { get; set; } = string.Empty;
public DateTime Expires { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using MadWorld.Backend.Identity.Application;
using MadWorld.Backend.Identity.Contracts;
using MadWorld.Backend.Identity.Domain.Users;
using MadWorld.Backend.Identity.Extensions;
using MadWorld.Shared.Infrastructure.Settings;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -24,15 +25,15 @@ public static void AddIdentityEndpoints(this WebApplication app)
.WithOpenApi();

account.MapPost("/JwtLogin",
([FromBody] JwtLoginRequest request, [FromServices] PostJwtLoginUseCase useCase) =>
useCase.PostJwtLogin(request))
([FromBody] JwtLoginRequest request, [FromServices] PostJwtLoginUseCase useCase, HttpContext context) =>
useCase.PostJwtLogin(request, context.Request.GetBaseUrl()))
.WithName("JwtLogin")
.WithOpenApi()
.AllowAnonymous();

account.MapPost("/JwtRefresh",
([FromBody] JwtRefreshRequest request, [FromServices] PostJwtRefreshUseCase useCase) =>
useCase.PostJwtRefresh(request))
([FromBody] JwtRefreshRequest request, [FromServices] PostJwtRefreshUseCase useCase, HttpContext context) =>
useCase.PostJwtRefresh(request, context.Request.GetBaseUrl()))
.WithName("JwtRefresh")
.WithOpenApi()
.AllowAnonymous();
Expand Down
13 changes: 13 additions & 0 deletions MadWorld/MadWorld.Backend.Identity/Extensions/RequestExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Microsoft.Extensions.Primitives;

namespace MadWorld.Backend.Identity.Extensions;

public static class RequestExtensions
{
public static string GetBaseUrl(this HttpRequest request)
{
request.Headers.TryGetValue("Origin", out var originValues);
var url = originValues.Count != 0 ? originValues[0]! : string.Empty;
return url.TrimEnd('/') + "/";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ public void Configure(EntityTypeBuilder<RefreshToken> builder)
{
builder.HasKey(x => x.Id);

builder.Property(x => x.Audience)
.IsRequired()
.HasMaxLength(RefreshToken.MaxLength);

builder.Property(x => x.Token)
.IsRequired()
.HasMaxLength(RefreshToken.MaxLength);
Expand Down
Loading

0 comments on commit 8ba6d5c

Please sign in to comment.