using System.Text.Json.Nodes; using w4c_workflows.Models.Credentials; namespace w4c_workflows.Services.Credentials; /// Tokens pulled out of an OAuth-style token response. public sealed record TokenSet( string AccessToken, string TokenType, int? ExpiresInSeconds, string? RefreshToken, string? Scope); /// /// Reads a token response using a type's extraction strategy. This is the /// counterpart to : injection places a token on a /// request, extraction finds it in a token endpoint's response (dot-paths such as /// authed_user.access_token). The OAuth refresh flow that consumes this is /// a later increment; the strategy is modelled and tested now. /// public static class CredentialExtractor { public static TokenSet? Extract(JsonObject tokenResponse, CredentialExtraction extraction) { var accessToken = ReadPath(tokenResponse, extraction.AccessTokenField); if (string.IsNullOrEmpty(accessToken)) return null; var expiresIn = int.TryParse(ReadPath(tokenResponse, extraction.ExpiresInField), out var seconds) ? seconds : (int?)null; return new TokenSet( accessToken, ReadPath(tokenResponse, extraction.TokenTypeField) ?? extraction.DefaultTokenType, expiresIn, ReadPath(tokenResponse, extraction.RefreshTokenField), ReadPath(tokenResponse, extraction.ScopeField)); } private static string? ReadPath(JsonObject root, string? path) { if (string.IsNullOrWhiteSpace(path)) return null; JsonNode? current = root; foreach (var segment in path.Split('.', StringSplitOptions.RemoveEmptyEntries)) { if (current is not JsonObject obj || !obj.TryGetPropertyValue(segment, out current)) return null; } return current is JsonValue value && value.TryGetValue(out var text) ? text : current?.ToJsonString(); } }