58 lines
2 KiB
C#
58 lines
2 KiB
C#
using System.Text.Json.Nodes;
|
|
using w4c_workflows.Models.Credentials;
|
|
|
|
namespace w4c_workflows.Services.Credentials;
|
|
|
|
/// <summary>Tokens pulled out of an OAuth-style token response.</summary>
|
|
public sealed record TokenSet(
|
|
string AccessToken,
|
|
string TokenType,
|
|
int? ExpiresInSeconds,
|
|
string? RefreshToken,
|
|
string? Scope);
|
|
|
|
/// <summary>
|
|
/// Reads a token response using a type's extraction strategy. This is the
|
|
/// counterpart to <see cref="CredentialInjector"/>: injection places a token on a
|
|
/// request, extraction finds it in a token endpoint's response (dot-paths such as
|
|
/// <c>authed_user.access_token</c>). The OAuth refresh flow that consumes this is
|
|
/// a later increment; the strategy is modelled and tested now.
|
|
/// </summary>
|
|
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<string>(out var text)
|
|
? text
|
|
: current?.ToJsonString();
|
|
}
|
|
}
|