@moesi/ogp
v0.1.0
Published
Browser-safe client and protocol primitives for the Operator Grant Protocol.
Maintainers
Readme
@moesi/ogp
Browser-safe client and protocol primitives for the opt-in Operator Grant Protocol (OGP).
The package creates immutable authorization requests, PKCE material, pushed authorization requests, claim challenges, and one-time claims. It never creates or exports an operator private key. The authority-bearing Kernel artifact is returned only as a recipient-encrypted envelope.
For hosted/self-hosted ceremonies, prepareAuthorization includes the exact
claim-transport algorithm, public key, and key ID in both requestId and
requestHash. The client and owner surfaces reject broker responses whose
delivery key, request URI, client ID, authorization URL, or callback binding
does not match. These hashes provide integrity, not identity: the relay
deployment must still authenticate the actor/client and authorize the complete
request through its registry adapter. Cross-origin cookie sessions must opt in
with credentials: "include"; custom authenticated transports can be supplied
through fetch.
The wire format, hashing rules, HTTP surface, wallet JSON-RPC methods,
extensible policy plugin contract, opt-in operating modes, and security
requirements are defined in docs/ogp-spec.md.
import {
createClaimTransportKeyPair,
createOgpClient,
decryptGrantEnvelope,
prepareAuthorization,
} from "@moesi/ogp";
const claimKeys = createClaimTransportKeyPair({
algorithm: "x25519-chacha20-poly1305",
keyId: "local-key-1",
});
const prepared = await prepareAuthorization({
request: {
organizationId: "org_123",
actorId: "agent_456",
chainId: "0xaa36a7",
account: "0x0000000000000000000000000000000000000001",
audience: "orchestra-web",
operator: {
type: "secp256k1",
publicKey: "0x02...",
},
policy: {
permissions: [],
rules: [],
},
validAfter: 0,
validUntil: 1_800_000_000,
nonce: "0x...",
adjustment: "attenuation-only",
},
claimTransport: claimKeys.transport,
});
const client = createOgpClient({
issuer: "https://ogp.example.com",
clientId: "my-cli",
redirectUri: "http://127.0.0.1:8787/callback",
});
const pushed = await client.pushAuthorization(prepared);
location.assign(pushed.authorizationUrl);
// After the owner-approved redirect, reject a state mismatch before using code.
const { code } = client.parseAuthorizationCallback(prepared, location.href);
const { challenge } = await client.requestClaimChallenge({
code,
codeVerifier: prepared.codeVerifier,
});
const proof = await signWithLocalOperatorCredential(challenge);
const { envelope } = await client.claimGrant({
code,
codeVerifier: prepared.codeVerifier,
proof,
});
const grant = await decryptGrantEnvelope({
request: prepared.request,
envelope,
keyPair: claimKeys,
});The caller must retain prepared.codeVerifier, prepared.state, the operator
credential, and the private claim-transport key locally. PKCE is required both
when obtaining the proof challenge and when claiming. The caller decrypts the
envelope locally and verifies its grantHash; neither private material nor the
plaintext Kernel enable artifact is sent to the relay.
Validity and first-party expiry-policy timestamps are whole Unix seconds and
must not exceed OGP_MAX_UNIX_TIMESTAMP_SECONDS (8_640_000_000_000), the
largest value that can be rendered as a portable ECMAScript ISO timestamp.
createOgpWalletClient binds the experimental wallet JSON-RPC methods
(ogp_requestGrant, ogp_getGrants, and ogp_revokeGrant) plus live
wallet_getCapabilities. It verifies the immutable request, effective grant,
policy hash, grant hash, artifact type, EIP-191 owner binding, and attenuation
relation before returning authority to the caller. The actor must also verify
that the recovered binding signer controls the requested Kernel account on the
requested chain. OgpPolicyRegistry provides fail-closed
validation, owner disclosure, enforcement labels, compilation, independent
verification, and permission/rule attenuation composition.
Use resolveOgpAuthorizationMode or createOgpAuthorizationRuntime for the
explicit hosted, self-hosted, and direct choices. Missing configuration
keeps the legacy direct mode; broker failure never causes automatic fallback.
Broker issuers require HTTPS, with HTTP allowed only for localhost or
127.0.0.1; other loopback schemes are rejected.
requestOperatorGrantsPerChain performs one chain/account ceremony at a time
and returns partial success without discarding successful grants.
