using Ory.Kratos.Client.Api; using System.Security.Claims; using Ory.Kratos.Client.Client; using System.Text.Encodings.Web; using Microsoft.Extensions.Options; using Microsoft.AspNetCore.Authentication; namespace khmer_eid_backend.Integrations.Ory; public class KratosHandler : AuthenticationHandler { private readonly FrontendApi _frontendApi; public KratosHandler( IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, IConfiguration config) : base(options, logger, encoder) { var cfg = new Configuration { BasePath = config["Ory:Kratos:PublicUrl"]! }; _frontendApi = new FrontendApi(cfg); } protected override async Task HandleAuthenticateAsync() { var authHeader = Request.Headers["Authorization"].ToString(); if (string.IsNullOrWhiteSpace(authHeader) || !authHeader.StartsWith("Bearer ")) return AuthenticateResult.NoResult(); var token = authHeader.Substring("Bearer ".Length).Trim(); try { var session = await _frontendApi.ToSessionAsync(xSessionToken: token); var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, session.Identity.Id), new Claim("phone", session.Identity.Traits.ToString() ?? "") }, Scheme.Name); var principal = new ClaimsPrincipal(identity); return AuthenticateResult.Success(new AuthenticationTicket(principal, Scheme.Name)); } catch (Exception ex) { Logger.LogError(ex, "Failed to authenticate Kratos session"); return AuthenticateResult.Fail("Invalid Kratos session token"); } } }