From 7a862a202ab4ccd9431ca68cd3ed0305a4d76df5 Mon Sep 17 00:00:00 2001 From: Jonathan Bourdon Date: Wed, 6 May 2026 15:36:49 -0400 Subject: [PATCH] fix: normalize Resend API key configuration --- README.md | 1 + .../Emailer/Services/ResendEmailSender.cs | 24 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f0949ad..470be70 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ http://:8080 For preprod deployment, configure the `POSTGRES_PASSWORD`, `RESEND_API_KEY`, `RESEND_FROM_EMAIL`, and `JWT_SIGNING_KEY` Gitea secrets. The deploy workflow writes the remote `.env` file before running the server deploy script. +Use the raw Resend API key value for `RESEND_API_KEY`, without a `Bearer ` prefix. ## Solution diff --git a/backend/src/Socialize.Api/Infrastructure/Emailer/Services/ResendEmailSender.cs b/backend/src/Socialize.Api/Infrastructure/Emailer/Services/ResendEmailSender.cs index ce5ee12..f3d9596 100644 --- a/backend/src/Socialize.Api/Infrastructure/Emailer/Services/ResendEmailSender.cs +++ b/backend/src/Socialize.Api/Infrastructure/Emailer/Services/ResendEmailSender.cs @@ -20,18 +20,24 @@ public class ResendEmailSender : IEmailSender _httpClient = httpClientFactory.CreateClient(); _options = options.Value; - if (string.IsNullOrWhiteSpace(_options.ApiKey)) + string apiKey = NormalizeApiKey(_options.ApiKey); + string fromEmail = _options.FromEmail?.Trim() ?? string.Empty; + + if (string.IsNullOrWhiteSpace(apiKey)) { throw new InvalidOperationException("Emailer:ApiKey is required when using Resend email delivery."); } - if (string.IsNullOrWhiteSpace(_options.FromEmail)) + if (string.IsNullOrWhiteSpace(fromEmail)) { throw new InvalidOperationException("Emailer:FromEmail is required when using Resend email delivery."); } + _options.ApiKey = apiKey; + _options.FromEmail = fromEmail; + _httpClient.DefaultRequestHeaders.Authorization = - new AuthenticationHeaderValue("Bearer", _options.ApiKey); + new AuthenticationHeaderValue("Bearer", apiKey); _httpClient.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); @@ -53,4 +59,16 @@ public class ResendEmailSender : IEmailSender $"Resend email failed: {response.StatusCode} - {body}"); } } + + private static string NormalizeApiKey(string? apiKey) + { + string normalized = apiKey?.Trim().Trim('"', '\'') ?? string.Empty; + const string bearerPrefix = "Bearer "; + if (normalized.StartsWith(bearerPrefix, StringComparison.OrdinalIgnoreCase)) + { + normalized = normalized[bearerPrefix.Length..].Trim(); + } + + return normalized; + } }