dpop

package
v1.0.98 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 13, 2026 License: MIT Imports: 31 Imported by: 0

Documentation

Overview

Package dpop implements the DPoP protocol primitives used by OAuth token requests and Lark OpenAPI requests. Key contains only a public key and a stable signer handle.

Index

Constants

View Source
const (
	ProofHeader            = "DPoP"
	Scheme                 = "DPoP"
	TokenType              = "DPoP"
	ClockSkewErrorCode     = 20153
	InvalidProofOAuthError = "invalid_dpop_proof"
)
View Source
const (

	// KeyStoreUnavailableHint is safe to use before or after a Token Endpoint
	// exchange because it makes no claim about whether a request was sent.
	KeyStoreUnavailableHint = "" /* 253-byte string literal not displayed */
	// KeyStorePreExchangeUnavailableHint adds the stronger guarantee available
	// only when key storage fails before the Token Endpoint request.
	KeyStorePreExchangeUnavailableHint = "no OAuth token request was sent; " + KeyStoreUnavailableHint
	// KeyAccessUnavailableHint covers an already-bound token whose key cannot be
	// loaded or used to sign the protected resource request.
	KeyAccessUnavailableHint = "" /* 284-byte string literal not displayed */
)
View Source
const HeartbeatPath = "/accounts/status/heartbeat"

Variables

View Source
var ErrInvalidProofResponse = errors.New("token endpoint returned " + InvalidProofOAuthError)

ErrInvalidProofResponse is a safe cause for typed errors derived from an InvalidProofOAuthError Token Endpoint response. It intentionally excludes the response description, token, proof, and key material.

View Source
var ErrKeyNotFound = errors.New("DPoP key not found")
View Source
var ErrRepeatedInvalidProof = errors.New("token endpoint rejected three consecutive DPoP proofs")

ErrRepeatedInvalidProof marks three consecutive explicit proof rejections during new token issuance. Callers own the preferred-mode fallback and key rollback.

Functions

func IsClockRecoverySignal

func IsClockRecoverySignal(code int, oauthError string) bool

IsClockRecoverySignal reports whether a Token Endpoint response carries the complete server signal that permits a one-time DPoP clock correction. The OAuth error comparison is deliberately exact.

func NormalizeHTU

func NormalizeHTU(rawURL string) (string, error)

NormalizeHTU produces the RFC 3986 form used by DPoP htu: scheme and host are lowercase, default ports/query/fragment/dot segments are removed, and percent encodings are canonicalized without changing path case.

func SynchronizeClock

func SynchronizeClock(ctx context.Context, httpClient *http.Client, brand core.LarkBrand, key *Key) error

SynchronizeClock obtains the Accounts server time before a DPoP token request. The calibrated clock is kept on the key; callers decide when the corresponding key metadata becomes part of their token transaction.

func WithBinding

func WithBinding(ctx context.Context, binding *Binding) context.Context

func WithTokenEndpointKey

func WithTokenEndpointKey(ctx context.Context, key *Key) context.Context

WithTokenEndpointKey marks an OAuth Token Endpoint request for proof generation at the network boundary. It carries signing capability only in memory and never serializes the private key.

Types

type AdjustableClock

type AdjustableClock struct {
	// contains filtered or unexported fields
}

AdjustableClock is safe for concurrent proof generation and clock recovery.

func NewClock

func NewClock(base Clock) *AdjustableClock

func NewClockWithState

func NewClockWithState(base Clock, state ClockState) *AdjustableClock

func (*AdjustableClock) Now

func (c *AdjustableClock) Now() time.Time

func (*AdjustableClock) RestoreState

func (c *AdjustableClock) RestoreState(state ClockState)

RestoreState replaces the persisted calibration without reading the system clock. Token records can use this to remain the atomic source of truth for a UAT and its proof clock.

func (*AdjustableClock) SetServerTime

func (c *AdjustableClock) SetServerTime(serverTime, localReceiveTime time.Time)

SetServerTime records serverTime-localReceiveTime as the shared DPoP clock offset used by proofs and DPoP-bound token lifetime calculations.

func (*AdjustableClock) State

func (c *AdjustableClock) State() ClockState

type Binding

type Binding struct {
	Token               string
	KeyID               string
	JKT                 string
	KeyStoreSecureLevel keysigner.SecurityLevel
	// contains filtered or unexported fields
}

Binding associates a token with the only key that may prove possession of it.

func BindingFromContext

func BindingFromContext(ctx context.Context) (*Binding, bool)

func NewBinding

func NewBinding(token string, key *Key) (*Binding, error)

func RestoreBinding

func RestoreBinding(token, keyID, expectedJKT string, key *Key) (*Binding, error)

func (*Binding) Key

func (b *Binding) Key() *Key

func (*Binding) SignProof

func (b *Binding) SignProof(method, rawURL string) (string, error)

func (*Binding) SignProofContext

func (b *Binding) SignProofContext(ctx context.Context, method, rawURL string) (string, error)

type Clock

type Clock interface {
	Now() time.Time
}

Clock supplies timestamps for DPoP proofs and DPoP-bound token lifetimes.

type ClockState

type ClockState struct {
	OffsetMillis   int64
	SyncedAtMillis int64
}

ClockState is the non-secret persistent state needed to restore a calibrated clock with its platform key.

type Key

type Key struct {
	// contains filtered or unexported fields
}

Key is a capability to sign with an ES256/P-256 key. It stores only the public key, a non-secret backend identifier, and the platform signer.

func (*Key) Clock

func (k *Key) Clock() *AdjustableClock

func (*Key) ID

func (k *Key) ID() string

func (*Key) Provider

func (k *Key) Provider() string

func (*Key) PublicJWK

func (k *Key) PublicJWK() (keysigner.PublicJWK, error)

func (*Key) SecurityLevel

func (k *Key) SecurityLevel() keysigner.SecurityLevel

func (*Key) SignProof

func (k *Key) SignProof(method, rawURL string) (string, error)

SignProof creates a one-use compact JWS.

func (*Key) SignProofContext

func (k *Key) SignProofContext(ctx context.Context, method, rawURL string) (string, error)

SignProofContext creates a one-use proof while preserving request cancellation through the platform signing boundary.

func (*Key) Thumbprint

func (k *Key) Thumbprint() (string, error)

Thumbprint computes the RFC 7638 SHA-256 JWK thumbprint.

type KeyStore

type KeyStore struct {
	// contains filtered or unexported fields
}

KeyStore coordinates ordered signing backends with the CLI secret store. Metadata records contain no private keys. L3 keeps its file unlock secret in a separate keychain entry; the signer owns its encrypted private-key files.

func NewKeyStore

func NewKeyStore(kc keychain.KeychainAccess) *KeyStore

func NewKeyStoreWithSigner

func NewKeyStoreWithSigner(kc keychain.KeychainAccess, signer keysigner.Signer) *KeyStore

NewKeyStoreWithSigner is an injection seam for platform implementations and hermetic tests. Production callers should use NewKeyStore.

func (*KeyStore) Delete

func (s *KeyStore) Delete(id string) error

func (*KeyStore) DeleteContext

func (s *KeyStore) DeleteContext(ctx context.Context, id string) error

func (*KeyStore) DeleteKeyContext

func (s *KeyStore) DeleteKeyContext(ctx context.Context, key *Key) error

DeleteKeyContext removes a key using the signer capability carried by the key itself. It is used to roll back a newly issued key before public metadata has been committed.

func (*KeyStore) EnsureContext

func (s *KeyStore) EnsureContext(ctx context.Context, id string) (*Key, error)

EnsureContext opens or creates the key for a stable non-secret identifier. It is used for process-cached tenant tokens so repeated CLI invocations do not leave one new key per token issuance.

func (*KeyStore) Generate

func (s *KeyStore) Generate() (*Key, error)

Generate creates a persistent P-256 key with the strongest usable backend. The caller must either Save it after the token transaction commits or delete it on failure.

func (*KeyStore) GenerateContext

func (s *KeyStore) GenerateContext(ctx context.Context) (*Key, error)

func (*KeyStore) Load

func (s *KeyStore) Load(id string) (*Key, error)

func (*KeyStore) LoadContext

func (s *KeyStore) LoadContext(ctx context.Context, id string) (*Key, error)

func (*KeyStore) PrepareReplaceableContext

func (s *KeyStore) PrepareReplaceableContext(ctx context.Context, id string) (*Key, bool, error)

PrepareReplaceableContext opens a stable key or replaces unreadable backend state when no persisted token can still be bound to that key. This is intended for TAT, whose token and Binding are process-local. UAT callers must use LoadContext so an unusable bound key requires re-authorization instead of silent rebinding. Created is true only when the caller owns a new key and must delete it if the token issuance transaction does not commit. The identifier is a namespace: each backend uses its own stable key within it.

func (*KeyStore) ProbeKeyWritableContext

func (s *KeyStore) ProbeKeyWritableContext(ctx context.Context, key *Key) error

ProbeKeyWritableContext validates metadata persistence and the exact signer already owned by a binding. It never selects or probes a different provider.

func (*KeyStore) ProbeWritableContext

func (s *KeyStore) ProbeWritableContext(ctx context.Context) error

ProbeWritableContext verifies both public-metadata persistence and the exact generate/sign/delete capability needed by a DPoP flow. It must run before a Token Endpoint request when DPoP is required.

func (*KeyStore) RequireKeyWritableContext

func (s *KeyStore) RequireKeyWritableContext(ctx context.Context, key *Key) error

RequireKeyWritableContext validates metadata persistence and the exact signer already owned by a binding, returning the token-flow error shape on failure.

func (*KeyStore) RequireWritableContext

func (s *KeyStore) RequireWritableContext(ctx context.Context) error

RequireWritableContext fails before a Token Endpoint request when the resulting DPoP binding could not be persisted safely.

func (*KeyStore) RequireWritableForReauthorizationContext

func (s *KeyStore) RequireWritableForReauthorizationContext(ctx context.Context) (bool, error)

RequireWritableForReauthorizationContext performs the ordinary writable probe and repairs a definitively lost software unlock secret once. The repair deletes software keys that can no longer be decrypted, so callers must use it only while explicitly issuing a replacement credential.

func (*KeyStore) Save

func (s *KeyStore) Save(key *Key) error

func (*KeyStore) SaveContext

func (s *KeyStore) SaveContext(ctx context.Context, key *Key) error

type Transport

type Transport struct {
	Base http.RoundTripper
}

Transport signs access-token requests at the final request boundary. Place it inside retry transports so each attempt receives a fresh proof. Callers own destination policy and must clear DPoP headers and context whenever they remove Authorization; this transport does not restrict request origins.

func (*Transport) BaseRoundTripper

func (t *Transport) BaseRoundTripper() http.RoundTripper

func (*Transport) RoundTrip

func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error)

func (*Transport) WithBaseRoundTripper

func (t *Transport) WithBaseRoundTripper(base http.RoundTripper) http.RoundTripper

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL