Auto-link verified Google sign-ins by email
This commit is contained in:
@@ -135,6 +135,15 @@ public sealed class AuthController : ControllerBase
|
||||
x => x.GoogleSubject == google.Subject || (!string.IsNullOrWhiteSpace(google.Email) && x.GoogleEmail == google.Email),
|
||||
cancellationToken);
|
||||
|
||||
if (user is null && google.EmailVerified && !string.IsNullOrWhiteSpace(google.Email))
|
||||
{
|
||||
user = await _users.FindByEmailAsync(google.Email);
|
||||
if (user is not null)
|
||||
{
|
||||
_logger.LogInformation("Auto-linking Google sign-in for existing local account {Email}", google.Email);
|
||||
}
|
||||
}
|
||||
|
||||
if (user is null)
|
||||
{
|
||||
return Unauthorized("This Google account is not linked to a Jobbjakt user yet.");
|
||||
@@ -145,6 +154,9 @@ public sealed class AuthController : ControllerBase
|
||||
user.GoogleSubject = google.Subject;
|
||||
user.GoogleEmail = google.Email;
|
||||
user.GoogleLinkedAt ??= DateTimeOffset.UtcNow;
|
||||
user.DisplayName ??= TrimOrNull(google.Name);
|
||||
user.FirstName ??= TrimOrNull(google.GivenName);
|
||||
user.LastName ??= TrimOrNull(google.FamilyName);
|
||||
await _users.UpdateAsync(user);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace JobTrackerApi.Services;
|
||||
|
||||
public sealed record GoogleTokenPrincipal(string Subject, string? Email, string? GivenName, string? FamilyName, string? Name);
|
||||
public sealed record GoogleTokenPrincipal(string Subject, string? Email, bool EmailVerified, string? GivenName, string? FamilyName, string? Name);
|
||||
|
||||
public interface IGoogleTokenValidator
|
||||
{
|
||||
@@ -56,9 +56,17 @@ public sealed class GoogleTokenValidator : IGoogleTokenValidator
|
||||
return new GoogleTokenPrincipal(
|
||||
Subject: subject,
|
||||
Email: principal.FindFirst("email")?.Value?.Trim(),
|
||||
EmailVerified: IsEmailVerified(principal),
|
||||
GivenName: principal.FindFirst("given_name")?.Value?.Trim(),
|
||||
FamilyName: principal.FindFirst("family_name")?.Value?.Trim(),
|
||||
Name: principal.FindFirst("name")?.Value?.Trim()
|
||||
);
|
||||
}
|
||||
|
||||
private static bool IsEmailVerified(System.Security.Claims.ClaimsPrincipal principal)
|
||||
{
|
||||
var raw = principal.FindFirst("email_verified")?.Value?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(raw)) return false;
|
||||
return string.Equals(raw, "true", StringComparison.OrdinalIgnoreCase) || raw == "1";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user