This is a Go implementation of the OAuth 2.0 Demonstrating Proof of Possession (DPoP) specification.
- RFC 9449 compliant DPoP proof generation and validation
- JTI-based replay attack prevention with configurable time windows
- Built-in integrations:
net/http
client and server middleware- gRPC interceptors
- Gin framework middleware
- Redis-backed JTI-replay prevention storage
- Ed25519 and RSA signing key support
- Context propagation throughout the API
- No external dependencies in core package
- Comprehensive test coverage
pkg/dpop
- Core DPoP implementation including proof generation and validation
- Implements the core RFC 9449 functionality
integrations/dpop_http
- Standardnet/http
client and server implementationsintegrations/dpop_grpc
- gRPC client and server interceptorsintegrations/dpop_gin
- Gin framework middlewareintegrations/jti_store_redis
- Redis-based proof storage and validation
import (
"crypto/ed25519"
"github.com/conductorone/dpop/pkg/dpop"
)
// Generate or load your private key
_, privateKey, _ := ed25519.GenerateKey(nil)
// Create a new proofer
proofer, err := dpop.NewProofer(privateKey)
if err != nil {
// Handle error
}
// Generate a DPoP proof
proof, err := proofer.CreateProof(ctx, "POST", "https://api.example.com/token")
import (
"crypto/ed25519"
"github.com/conductorone/dpop/integrations/dpop_http"
)
// Generate or load your private key
_, privateKey, _ := ed25519.GenerateKey(nil)
// Create a DPoP-enabled HTTP transport
transport, err := dpop_http.NewTransport(
http.DefaultTransport,
privateKey,
tokenSource, // your oauth2.TokenSource
)
if err != nil {
// Handle error
}
// Create a client with the transport
client := &http.Client{Transport: transport}
// DPoP proofs are automatically attached to requests
resp, err := client.Get("https://api.example.com/resource")
import (
"crypto/ed25519"
"github.com/conductorone/dpop/integrations/dpop_grpc"
)
// Generate or load your private key
_, privateKey, _ := ed25519.GenerateKey(nil)
// Create and use a DPoP interceptor
interceptor, err := dpop_grpc.NewClientInterceptor(privateKey)
if err != nil {
// Handle error
}
conn, err := grpc.Dial(
address,
grpc.WithUnaryInterceptor(interceptor.UnaryClientInterceptor()),
)
If you discover a security issue, please report it by sending an email to security@conductorone.com. Please do not file a public issue or pull request.
We appreciate your help in making this project more secure and will acknowledge your contributions.
This project is licensed under the Apache License, Version 2.0. See the LICENSE file for details.