summary refs log tree commit diff
path: root/extra/admin-api/Interop/Spacebar.Interop.Authentication/SpacebarAuthenticationService.cs
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2026-02-03 03:10:10 +0100
committerRory& <root@rory.gay>2026-02-03 03:15:59 +0100
commita06e8f723b5c81945d8f226e8d77d95312cb8d85 (patch)
tree3b37c13bb890620168b0b81a20e37c75de8b3241 /extra/admin-api/Interop/Spacebar.Interop.Authentication/SpacebarAuthenticationService.cs
parentUpdate C# db models (diff)
downloadserver-ts-a06e8f723b5c81945d8f226e8d77d95312cb8d85.tar.xz
Abstract out C# auth
Diffstat (limited to 'extra/admin-api/Interop/Spacebar.Interop.Authentication/SpacebarAuthenticationService.cs')
-rw-r--r--extra/admin-api/Interop/Spacebar.Interop.Authentication/SpacebarAuthenticationService.cs49
1 files changed, 49 insertions, 0 deletions
diff --git a/extra/admin-api/Interop/Spacebar.Interop.Authentication/SpacebarAuthenticationService.cs b/extra/admin-api/Interop/Spacebar.Interop.Authentication/SpacebarAuthenticationService.cs
new file mode 100644

index 00000000..7b4ad1c8 --- /dev/null +++ b/extra/admin-api/Interop/Spacebar.Interop.Authentication/SpacebarAuthenticationService.cs
@@ -0,0 +1,49 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Security.Cryptography; +using ArcaneLibs.Collections; +using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.Tokens; +using Spacebar.Models.Db.Contexts; +using Spacebar.Models.Db.Models; + +namespace Spacebar.Interop.Authentication; + +public class SpacebarAuthenticationService(ILogger<SpacebarAuthenticationService> logger, SpacebarDbContext db, SpacebarAuthenticationConfiguration config) { + private static readonly ExpiringSemaphoreCache<User> UserCache = new(); + + public async Task<TokenValidationResult?> ValidateTokenAsync(string token) { + var handler = new JwtSecurityTokenHandler(); + var secretFile = await File.ReadAllTextAsync(config.PublicKeyPath); + var key = ECDsa.Create(ECCurve.NamedCurves.nistP256); + key.ImportFromPem(secretFile); + + var res = await handler.ValidateTokenAsync(token, new TokenValidationParameters { + IssuerSigningKey = new ECDsaSecurityKey(key), + ValidAlgorithms = ["ES512"], + LogValidationExceptions = true, + // These are required to be false for the token to be valid as they aren't provided by the token + ValidateIssuer = false, + ValidateLifetime = false, + ValidateAudience = false, + // TryAllIssuerSigningKeys = true + }); + + if ((!res.IsValid || res.Exception is not null) && !config.DisableAuthentication) { + logger.LogInformation("Invalid token"); + throw res.Exception ?? new UnauthorizedAccessException("Token was invalid"); + } + + return res; + } + + public async Task<User> GetCurrentUserAsync(string token) { + var res = await ValidateTokenAsync(token); + return await UserCache.GetOrAdd(token, + async () => { + var uid = config.OverrideUid ?? res?.ClaimsIdentity.Claims.First(x => x.Type == "id").Value; + if (string.IsNullOrWhiteSpace(uid)) throw new InvalidOperationException("No user ID specified, is the access token valid?"); + return await db.Users.FindAsync(uid) ?? throw new InvalidOperationException(); + }, + config.AuthCacheExpiry); + } +} \ No newline at end of file