37 lines
1.6 KiB
C#
37 lines
1.6 KiB
C#
using HuntingAppApi.Models;
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
namespace HuntingAppApi.Services;
|
|
|
|
public sealed class ExternalTokenValidator(HttpClient httpClient)
|
|
{
|
|
public async Task<ExternalUserInfo> ValidateAsync(string provider, string idToken, CancellationToken ct)
|
|
{
|
|
provider = provider.ToLowerInvariant();
|
|
|
|
// Production note: This is intentionally simple. For stricter production validation,
|
|
// validate issuer, audience/client_id and signature using OIDC metadata/JWKS.
|
|
var url = provider switch
|
|
{
|
|
"google" => $"https://oauth2.googleapis.com/tokeninfo?id_token={Uri.EscapeDataString(idToken)}",
|
|
"microsoft" => $"https://login.microsoftonline.com/common/oauth2/v2.0/tokeninfo?id_token={Uri.EscapeDataString(idToken)}",
|
|
_ => throw new ArgumentException("Unsupported provider")
|
|
};
|
|
|
|
var json = await httpClient.GetStringAsync(url, ct);
|
|
var obj = JObject.Parse(json);
|
|
var sub = obj.Value<string>("sub") ?? throw new InvalidOperationException("Token has no sub claim");
|
|
var name = obj.Value<string>("name") ?? obj.Value<string>("preferred_username") ?? obj.Value<string>("email") ?? "User";
|
|
|
|
return new ExternalUserInfo
|
|
{
|
|
Provider = provider,
|
|
Subject = sub,
|
|
Email = obj.Value<string>("email") ?? obj.Value<string>("preferred_username"),
|
|
EmailVerified = obj.Value<string>("email_verified") == "true" || obj.Value<bool?>("email_verified") == true,
|
|
DisplayName = name,
|
|
AvatarUrl = obj.Value<string>("picture")
|
|
};
|
|
}
|
|
}
|