Newer
Older
Warehouse / src / Infrastructure / Authentication / External / Services / ExternalAuthenticationVerifier.cs
@Derek Comartin Derek Comartin on 22 Aug 2023 2 KB Init
using Google.Apis.Auth;
using MyWarehouse.Infrastructure.Authentication.External.Exceptions;
using MyWarehouse.Infrastructure.Authentication.External.Model;
using MyWarehouse.Infrastructure.Authentication.Settings;
using System.ComponentModel;

namespace MyWarehouse.Infrastructure.Authentication.External.Services;

public class ExternalAuthenticationVerifier : IExternalAuthenticationVerifier
{
    private readonly ExternalAuthenticationSettings _externalAuthSettings;

    public ExternalAuthenticationVerifier(ExternalAuthenticationSettings settings)
    {
        _externalAuthSettings = settings;
    }

    public Task<(bool success, ExternalUserData? userData)> Verify(ExternalAuthenticationProvider provider, string idToken)
        => provider switch
        {
            ExternalAuthenticationProvider.Google => AuthenticateGoogleToken(idToken),
            _ => throw new InvalidEnumArgumentException($"Support for provider '{provider}' is not implemented.")
        };

    private async Task<(bool success, ExternalUserData? userData)> AuthenticateGoogleToken(string idToken)
    {
        if (string.IsNullOrWhiteSpace(_externalAuthSettings.GoogleClientId))
        {
            throw new ExternalAuthenticationSetupException(provider: "Google");
        }

        GoogleJsonWebSignature.Payload data;
        try
        {
            var settings = new GoogleJsonWebSignature.ValidationSettings()
            {
                Audience = new[] { _externalAuthSettings.GoogleClientId }
            };
            data = await GoogleJsonWebSignature.ValidateAsync(idToken, settings);
        }
        catch (Exception ex)
        {
            if (ex is InvalidJwtException)
            {
                return (false, null);
            }
            else
            {
                throw new ExternalAuthenticationPreventedException(ex);
            }
        }

        return (
            success: true,
            userData: new ExternalUserData()
            {
                Email = data.Email,
                EmailVerified = data.EmailVerified,
                FullName = data.Name,
                LastName = data.FamilyName,
                FirstName = data.GivenName
            }
        );
    }
}