Documentation
¶
Overview ¶
Package dpop implements Demonstrating Proof of Possession (DPoP) per RFC 9449. DPoP binds access tokens to cryptographic key pairs held by clients, preventing stolen tokens from being used without the private key.
Index ¶
- Constants
- Variables
- func ComputeAccessTokenHash(accessToken string) string
- func ComputeThumbprint(publicKey *ecdsa.PublicKey) (string, error)
- func CreateProof(kp *KeyPair, method, uri string) (string, error)
- func CreateProofWithOptions(kp *KeyPair, method, uri string, opts ProofOptions) (string, error)
- func GetThumbprint(ctx context.Context) string
- func IsValidHTTPMethod(method string) bool
- func Middleware(config MiddlewareConfig) func(http.Handler) http.Handler
- func OptionalDPoP(verifier *Verifier) func(http.Handler) http.Handler
- func RequireDPoP(verifier *Verifier) func(http.Handler) http.Handler
- func VerifyTokenBinding(tokenThumbprint string, proofThumbprint string) error
- type JWK
- type KeyPair
- type MiddlewareConfig
- type ParsedProof
- type ProofClaims
- type ProofHeader
- type ProofOptions
- type SerializedKeyPair
- type VerificationConfig
- type VerificationRequest
- type VerificationResult
- type Verifier
Constants ¶
const ( // ContextKeyVerificationResult is the context key for the verification result. ContextKeyVerificationResult contextKey = "dpop_verification_result" // ContextKeyThumbprint is the context key for the JWK thumbprint. ContextKeyThumbprint contextKey = "dpop_thumbprint" )
const ( // HeaderDPoP is the header name for DPoP proofs. HeaderDPoP = "DPoP" // HeaderAuthorization is the standard Authorization header. HeaderAuthorization = "Authorization" // AuthSchemeBearer is the Bearer authorization scheme. AuthSchemeBearer = "Bearer" // AuthSchemeDPoP is the DPoP authorization scheme. AuthSchemeDPoP = "DPoP" )
Header names for DPoP.
const (
// DPoPTokenType is the required typ header value for DPoP proofs.
DPoPTokenType = "dpop+jwt"
)
Variables ¶
var ( // ErrInvalidKey is returned when a key is malformed or invalid. ErrInvalidKey = errors.New("invalid key") // ErrUnsupportedAlgorithm is returned for unsupported cryptographic algorithms. ErrUnsupportedAlgorithm = errors.New("unsupported algorithm") )
var ( // ErrInvalidProof is returned when a DPoP proof is malformed or invalid. ErrInvalidProof = errors.New("invalid DPoP proof") // ErrMethodMismatch is returned when the htm claim doesn't match the request method. ErrMethodMismatch = errors.New("HTTP method mismatch") // ErrURIMismatch is returned when the htu claim doesn't match the request URI. ErrURIMismatch = errors.New("HTTP URI mismatch") // ErrTokenHashMismatch is returned when the ath claim doesn't match the access token hash. ErrTokenHashMismatch = errors.New("access token hash mismatch") // ErrProofExpired is returned when a DPoP proof's iat is too old. ErrProofExpired = errors.New("DPoP proof expired") // ErrNonceMismatch is returned when the nonce claim doesn't match the expected nonce. ErrNonceMismatch = errors.New("nonce mismatch") )
var ValidHTTPMethods = map[string]bool{ "GET": true, "HEAD": true, "POST": true, "PUT": true, "DELETE": true, "CONNECT": true, "OPTIONS": true, "TRACE": true, "PATCH": true, }
ValidHTTPMethods contains the valid HTTP methods for DPoP proofs.
Functions ¶
func ComputeAccessTokenHash ¶
ComputeAccessTokenHash computes the base64url-encoded SHA-256 hash of an access token. This is used for the ath (access token hash) claim in DPoP proofs.
func ComputeThumbprint ¶
ComputeThumbprint computes the JWK thumbprint per RFC 7638 for an ECDSA public key. For EC keys, the required members are: crv, kty, x, y (in lexicographic order).
func CreateProof ¶
CreateProof creates a DPoP proof JWT for the given request. The proof is signed with the key pair's private key and embeds the public key in the header.
func CreateProofWithOptions ¶
func CreateProofWithOptions(kp *KeyPair, method, uri string, opts ProofOptions) (string, error)
CreateProofWithOptions creates a DPoP proof JWT with optional parameters.
func GetThumbprint ¶
GetThumbprint retrieves the DPoP thumbprint from the request context.
func IsValidHTTPMethod ¶
IsValidHTTPMethod checks if the given method is a valid HTTP method.
func Middleware ¶
func Middleware(config MiddlewareConfig) func(http.Handler) http.Handler
Middleware creates HTTP middleware that validates DPoP proofs.
func OptionalDPoP ¶
OptionalDPoP is a helper function to create middleware that accepts but doesn't require DPoP.
func RequireDPoP ¶
RequireDPoP is a helper function to create middleware that requires DPoP.
func VerifyTokenBinding ¶
VerifyTokenBinding verifies that an access token's cnf.jkt claim matches the thumbprint from a verified DPoP proof.
Types ¶
type JWK ¶
type JWK struct {
Kty string `json:"kty"` // Key type (EC)
Crv string `json:"crv"` // Curve (P-256)
X string `json:"x"` // X coordinate
Y string `json:"y"` // Y coordinate
Alg string `json:"alg,omitempty"` // Algorithm (ES256)
}
JWK represents a JSON Web Key for embedding in DPoP proof headers.
func (*JWK) Thumbprint ¶
Thumbprint computes and returns the JWK thumbprint for this key.
type KeyPair ¶
type KeyPair struct {
// PrivateKey is the ECDSA private key for signing proofs.
PrivateKey *ecdsa.PrivateKey
// Thumbprint is the JWK thumbprint (RFC 7638) of the public key.
Thumbprint string
}
KeyPair represents an ES256 key pair for DPoP.
func DeserializeKeyPair ¶
func DeserializeKeyPair(s *SerializedKeyPair) (*KeyPair, error)
DeserializeKeyPair reconstructs a key pair from its serialized form.
func DeserializeKeyPairJSON ¶
DeserializeKeyPairJSON reconstructs a key pair from JSON bytes.
func GenerateKeyPair ¶
GenerateKeyPair creates a new ES256 (P-256/secp256r1) key pair for DPoP. The thumbprint is computed per RFC 7638 using SHA-256.
func (*KeyPair) Serialize ¶
func (kp *KeyPair) Serialize() (*SerializedKeyPair, error)
Serialize converts the key pair to a serializable format.
func (*KeyPair) SerializeJSON ¶
SerializeJSON serializes the key pair to JSON bytes.
type MiddlewareConfig ¶
type MiddlewareConfig struct {
// Verifier is the DPoP verifier to use.
Verifier *Verifier
// RequireDPoP when true rejects requests without DPoP proofs.
// When false, requests without DPoP proofs are allowed through.
RequireDPoP bool
// ExtractAccessToken is a function to extract the access token from the request.
// If nil, the middleware extracts from the Authorization header.
ExtractAccessToken func(r *http.Request) string
// OnError is called when verification fails.
// If nil, a 401 Unauthorized response is sent.
OnError func(w http.ResponseWriter, r *http.Request, err error)
}
MiddlewareConfig contains configuration for the DPoP middleware.
type ParsedProof ¶
type ParsedProof struct {
// Claims contains the proof claims.
Claims *ProofClaims
// PublicKey is the public key extracted from the jwk header.
PublicKey *ecdsa.PublicKey
// Thumbprint is the JWK thumbprint of the public key.
Thumbprint string
}
ParsedProof contains the parsed and validated DPoP proof.
func ParseProof ¶
func ParseProof(proofString string) (*ParsedProof, error)
ParseProof parses a DPoP proof JWT without verifying it against request parameters. Use this for initial parsing before validation.
type ProofClaims ¶
type ProofClaims struct {
jwt.RegisteredClaims
// HTTPMethod is the HTTP method of the request (htm claim).
// REQUIRED. The value of the HTTP method of the request to which the JWT is attached.
HTTPMethod string `json:"htm"`
// HTTPURI is the HTTP URI of the request (htu claim).
// REQUIRED. The HTTP target URI, without query and fragment parts.
HTTPURI string `json:"htu"`
// AccessTokenHash is the base64url-encoded SHA-256 hash of the access token (ath claim).
// REQUIRED when the DPoP proof is sent with a request for a protected resource.
AccessTokenHash string `json:"ath,omitempty"`
// Nonce is the server-provided nonce value (nonce claim).
// Used for replay protection when the server issues nonces.
Nonce string `json:"nonce,omitempty"`
}
ProofClaims represents the claims for a DPoP proof JWT per RFC 9449.
func NewProofClaims ¶
func NewProofClaims(method, uri string, accessToken string) *ProofClaims
NewProofClaims creates a new DPoP proof claims structure. The method and uri parameters are required. The accessToken parameter is optional - if provided, the ath claim will be computed.
func (*ProofClaims) WithAccessToken ¶
func (c *ProofClaims) WithAccessToken(accessToken string) *ProofClaims
WithAccessToken computes and sets the ath claim from an access token.
func (*ProofClaims) WithNonce ¶
func (c *ProofClaims) WithNonce(nonce string) *ProofClaims
WithNonce adds a server-provided nonce to the claims.
type ProofHeader ¶
type ProofHeader struct {
Algorithm string `json:"alg"` // Algorithm (ES256, ES384, ES512)
Type string `json:"typ"` // MUST be "dpop+jwt"
JWK *JWK `json:"jwk"` // Public key
}
ProofHeader represents the JWT header for a DPoP proof. The header MUST include the public key (jwk) and MUST have typ=dpop+jwt.
type ProofOptions ¶
type ProofOptions struct {
// AccessToken is the access token to bind to the proof (for ath claim).
AccessToken string //nolint:gosec // G117: field holds runtime token value
// Nonce is a server-provided nonce for replay protection.
Nonce string
}
ProofOptions contains optional parameters for creating a DPoP proof.
type SerializedKeyPair ¶
type SerializedKeyPair struct {
PrivateKeyD string `json:"d"` // Private key scalar
PublicKeyX string `json:"x"` // Public key X coordinate
PublicKeyY string `json:"y"` // Public key Y coordinate
Curve string `json:"crv"` // Curve name
Thumbprint string `json:"thumbprint"` // JWK thumbprint
}
Serialize serializes the key pair for storage. The private key is encoded in PKCS#8 format and base64url encoded.
type VerificationConfig ¶
type VerificationConfig struct {
// MaxAge is the maximum age of a DPoP proof (based on iat claim).
// Default: 5 minutes.
MaxAge time.Duration
// AllowedClockSkew is the maximum clock skew to allow when validating iat.
// Default: 30 seconds.
AllowedClockSkew time.Duration
// RequireAccessTokenBinding when true requires the ath claim to be present
// and match the provided access token hash.
RequireAccessTokenBinding bool
// NonceValidator is an optional function to validate server-provided nonces.
// If set and returns an error, verification fails with ErrNonceMismatch.
NonceValidator func(ctx context.Context, nonce string) error
}
VerificationConfig contains configuration for DPoP proof verification.
func DefaultVerificationConfig ¶
func DefaultVerificationConfig() VerificationConfig
DefaultVerificationConfig returns the default verification configuration.
type VerificationRequest ¶
type VerificationRequest struct {
// Proof is the DPoP proof JWT string.
Proof string
// Method is the HTTP method of the request (e.g., "POST").
Method string
// URI is the HTTP URI of the request (scheme + host + path, no query or fragment).
URI string
// AccessToken is the access token to verify binding against (optional).
// Required if VerificationConfig.RequireAccessTokenBinding is true.
AccessToken string //nolint:gosec // G117: field holds runtime token value
// ExpectedNonce is the expected server-provided nonce (optional).
ExpectedNonce string
}
VerificationRequest contains the parameters for verifying a DPoP proof.
type VerificationResult ¶
type VerificationResult struct {
// Thumbprint is the JWK thumbprint of the public key used to sign the proof.
Thumbprint string
// JTI is the unique identifier of the proof.
JTI string
// IssuedAt is when the proof was created.
IssuedAt time.Time
}
VerificationResult contains the result of a successful verification.
func GetVerificationResult ¶
func GetVerificationResult(ctx context.Context) *VerificationResult
GetVerificationResult retrieves the DPoP verification result from the request context.
type Verifier ¶
type Verifier struct {
// contains filtered or unexported fields
}
Verifier verifies DPoP proofs.
func NewVerifier ¶
func NewVerifier(config VerificationConfig) *Verifier
NewVerifier creates a new DPoP verifier with the given configuration.
func (*Verifier) Verify ¶
func (v *Verifier) Verify(ctx context.Context, req VerificationRequest) (*VerificationResult, error)
Verify verifies a DPoP proof against the given request parameters.