using FastEndpoints; using GB5Shared.DTO.Framework.Enum; using GB5Shared.DTO.Framework.ResponseStandard; using PartnerBLL.Auth; namespace PartnerSL.EndPoints.Auth { // Public, pre-auth token-issuance endpoint — the partner has no session/LoginDTO yet at this // point (that's the whole reason this endpoint exists), so it's a raw Endpoint<,>, not // BaseEndpoint<,> — mirrors GetPublicBrandByConnection's identical "anonymous, no Login header" // shape, the only other pre-auth endpoint in this module. // // A partner backend exchanges its existing TPARTNERAPIKEY secret here ONCE for a short-lived // signed JWT, then calls Entitlement (or any other PartnerM2MJwtBearer-protected API) with // that token via a normal Bearer header — instead of sending the raw secret on every call, or // relying on an unauthenticated PartnerProductId query parameter. public class GetPartnerToken : Endpoint> { private readonly IPartnerTokenBLL _partnerTokenBLL; public GetPartnerToken(IPartnerTokenBLL partnerTokenBLL) => _partnerTokenBLL = partnerTokenBLL; public override void Configure() { Post("/PartnerToken/AuthToken"); AllowAnonymous(); } public class PartnerTokenRequest { /// The same secret value a partner already sends via the X-Api-Key header /// today — exchanged here once instead of presented on every call. public string ApiKey { get; set; } = string.Empty; } public override async Task HandleAsync(PartnerTokenRequest req, CancellationToken ct) { var result = await _partnerTokenBLL.IssueTokenAsync(req.ApiKey, ct).ConfigureAwait(false); if (result.Status != PartnerTokenResultStatus.Success) { await Send.ResponseAsync(new ResponseStandardDTO { Body = "", ErrorBody = "Invalid or expired API key.", Status = FrameworkEnumDTO.ResponseStatus.Failed }, 401, ct); return; } await Send.ResponseAsync(new ResponseStandardDTO { Body = new { AccessToken = result.AccessToken, ExpiresOn = result.ExpiresOn, TokenType = "Bearer" }, Status = FrameworkEnumDTO.ResponseStatus.Ok }, 200, ct); } } }