Pre-issued grants — .NET SDK¶
A pre-issued grant (protocol 1.6.0) lets its bearer act while the NA is out
of reach: the NA signs a CapabilityGrant before the bearer acts, with a
capability set, a closed parameter envelope, a use budget and a validity of at
most 24 hours. The bearer signs each use with its key and uploads it once the
NA is back. Grants are off unless the NA runs with EVIDENCE_GRANTS=on.
The .NET SDK checks a grant’s NA signature from 1.6.0 (Offline Verification — .NET SDK). From 1.9.0 it also has the grants’ rules, calls the NA’s grant routes and holds a grant, as the TypeScript SDK does. Every option is in the SDK’s README.
Issuing and revoking¶
var issued = await ops.Grants.IssueGrant(new IssueGrantRequest
{
BearerKeyId = "device-key", // a registered executor key
Capabilities = ["secret.rotate"],
AttestationId = attestation.AttestationId, // or an Agreement the NA trusts
ValidUntil = DateTimeOffset.UtcNow.AddHours(4),
MaxUses = 3,
ParameterEnvelope = new Dictionary<string, EnvelopeParameter>
{
["lifetime_days"] = new(true, null, null,
new NumericRange("integer", GrantNumber.Of(1), GrantNumber.Of(60), false, false)),
},
});
// issued.Grant; issued.TimeToken, as the NA signed it, for the first use
IssueGrantandRevokeGrantneed the privileged tier;Grants,AllGrants,Grant,GrantUsesandAllGrantUsesthe read tier.The NA refuses a grant an applied policy could deny (
ValidationException,grant_gate_may_deny), and a time token for a grant that can no longer be used (ConflictException:grant_expired,grant_revoked,grant_budget_exhaustedorgrant_bearer_key_retired).
Acting within a grant¶
A GrantHolder acts within a grant while the NA cannot be reached, and keeps
each use in the record outbox until the NA is back:
using var device = new GenesisMeshClient(new ClientOptions
{
BaseUrl = "https://na.example",
SigningKey = operatorSeed, KeyId = "ops", // evaluates when the holder falls back
RecordOutbox = new FileRecordOutbox("/var/lib/site/records"),
});
var holder = new GrantHolder(new GrantHolderOptions
{
Client = device,
Signer = bearerSigner, // the grant's bearer key
NAKeys = naKeyHistory,
Grant = issued.Grant, TimeToken = issued.TimeToken, // or State, to resume
Persist = (state, ct) => SaveAsync(state, ct), // after every change
});
var result = await holder.Act(new GrantActRequest
{
Capability = "secret.rotate",
RequestParameters = new Dictionary<string, object?> { ["lifetime_days"] = 30 },
ResourceId = "kv:site-7/api-key", ResourceAction = ResourceActions.Rotate,
Fallback = new GrantFallback { Justification = "the site is cut off", Verify = verification },
}, async (authority, ct) =>
{
// authority.Path: "grant", or "decision" / "break_glass" when the grant could not be used
return new ActionReport<string> { ExecutionParameters = new Dictionary<string, object?> { ["version_id"] = "v9" } };
});
var synced = await holder.Sync(); // on reconnect: the revocation feed, a fresh time token, the record outbox
Before each change the holder checks the grant offline, in the NA’s order: secret material, the bearer key’s resource prefix, the capability, the closed envelope, the budget, the validity, the revocation feed it holds, and the uses its time token has left. A request outside the grant throws
GrantRefusedException, and nothing runs.Each use takes the next place in the grant’s chain, and is never dated before its time token or the previous use.
When the grant cannot be used (it ended, or its budget or time token is spent, or it is revoked), the holder falls back to a governed action with break-glass (Governed actions and records — .NET SDK). An NA that answers decides, and a DENY is never broken through. Without a fallback it throws
GrantUnusableException.GrantHolderStateis the JSON the TypeScript SDK’s holder keeps, so a device can move between the SDKs.
The rules, offline¶
GrantRules and GrantRecords hold the grants’ rules as the reference has
them:
GrantNumberreads a number as every implementation does: an integral number is an integer, and comparisons are exact.GrantRules.Parameterreads an envelope parameter (one_of,subset_ofornumber_range).EnvelopeProblemsays why a use’s parameters fall outside a grant’s closed envelope.GrantRules.UseProblemgives the first rule a use breaks, in the reference’s order: capability, envelope, budget, time token, order, validity, upload time and revocation.GrantRecords.SignUseandSignTimeTokenRequestsign with the bearer key, and refuse first what the NA would refuse.OfflineVerifier.VerifyTimeToken,VerifyGrantRevocation,VerifyGrantUseandVerifyTimeTokenRequestcheck the records’ signatures.
An export verified offline checks each grant use against its grant and chain (Offline Verification — .NET SDK).