{"id":28995094,"url":"https://github.com/axiscommunications/go-dpop","last_synced_at":"2025-06-25T04:06:32.983Z","repository":{"id":188797602,"uuid":"677365129","full_name":"AxisCommunications/go-dpop","owner":"AxisCommunications","description":"DPoP for golang clients and servers","archived":false,"fork":false,"pushed_at":"2024-11-19T13:56:34.000Z","size":63,"stargazers_count":5,"open_issues_count":2,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-11-19T14:54:07.845Z","etag":null,"topics":["dpop","golang-library","oauth2"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AxisCommunications.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-11T11:45:49.000Z","updated_at":"2024-11-19T13:55:51.000Z","dependencies_parsed_at":null,"dependency_job_id":"261effad-9ba5-448a-bee3-899ca53db884","html_url":"https://github.com/AxisCommunications/go-dpop","commit_stats":null,"previous_names":["axiscommunications/go-dpop"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/AxisCommunications/go-dpop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxisCommunications%2Fgo-dpop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxisCommunications%2Fgo-dpop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxisCommunications%2Fgo-dpop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxisCommunications%2Fgo-dpop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AxisCommunications","download_url":"https://codeload.github.com/AxisCommunications/go-dpop/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxisCommunications%2Fgo-dpop/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261801988,"owners_count":23211664,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dpop","golang-library","oauth2"],"created_at":"2025-06-25T04:06:30.834Z","updated_at":"2025-06-25T04:06:32.946Z","avatar_url":"https://github.com/AxisCommunications.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# go-dpop\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/AxisCommunications/go-dpop.svg)](https://pkg.go.dev/github.com/AxisCommunications/go-dpop)\n[![Coverage Status](https://badge.coveralls.io/repos/github/AxisCommunications/go-dpop/badge.svg?branch=main)](https://badge.coveralls.io/github/AxisCommunications/go-dpop?branch=main)\n\nOAuth 2.0 Demonstrating Proof of Possession (DPoP)\n\nThis package tries to implement [RFC-9449](https://datatracker.ietf.org/doc/html/rfc9449)\n\n## Supported key algorithms\n\nSupported:\n\n- ES256, ES384, ES521\n- RS256, PS256\n- Ed25519\n\n## How to use\n\n### Authorization server\n\nAn authorization server needs to parse the incoming proof in order to associate the public key of the proof with the bound access token.  \nIt should parse the proof to ensure that the sender of the proof has access to the private key.\n\n```go\nimport \"github.com/AxisCommunications/go-dpop\"\n\nproof, err := dpop.Parse(proofString, dpop.POST, \u0026httpUrl, dpop.ParseOptions{\n    Nonce:      \"\",\n    TimeWindow: \u0026duration,\n  })\n// Check the error type to determine response\nif err != nil {\n  if ok := errors.Is(err, dpop.ErrInvalidProof); ok {\n    // Return 'invalid_dpop_proof'\n  }\n}\n\n// proof is valid, get public key to associate with access token\njkt := proof.PublicKey()\n\n// Continue\n```\n\n### Resource server\n\nResource servers need to do the same proof validation that authorization servers do but also check that the proof and access token are bound correctly.\n\n```go\nimport \"github.com/AxisCommunications/go-dpop\"\n\nproof, err := dpop.Parse(proofString, dpop.POST, \u0026httpUrl, dpop.ParseOptions{\n    Nonce:      \"\",\n    TimeWindow: \u0026duration,\n  })\n// Check the error type to determine response\nif err != nil {\n  if ok := errors.Is(err, dpop.ErrInvalidProof); ok {\n    // Return 'invalid_dpop_proof'\n  }\n}\n\n// Hash the token with base64 and SHA256\n// Get the access token JWT (introspect if needed)\n// Parse the access token JWT and verify the signature\n\nerr = proof.Validate(accessTokenHash, accessTokenJWT)\n// Check the error type to determine response\nif err != nil {\n  if ok := errors.Is(err, dpop.ErrInvalidProof); ok {\n    // Return 'invalid_dpop_proof'\n  }\n  if ok := errors.Is(err, dpop.ErrIncorrectAccessTokenClaimsType); ok {\n    // Return 'invalid_token'\n  }\n}\n\n// Continue\n```\n\n### Client\n\nA client can generate proofs that authorization and resource servers can validate.\n\n```go\nimport \"github.com/AxisCommunications/go-dpop\"\n\n// Setup the claims of the proof\nclaims := \u0026dpop.ProofTokenClaims{\n  RegisteredClaims: \u0026jwt.RegisteredClaims{\n    Issuer:    \"test\",\n    Subject:   \"sub\",\n    IssuedAt:  jwt.NewNumericDate(time.Now()),\n    ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute)),\n    ID:        \"id\",\n  },\n  Method: dpop.POST,\n  URL:    \"https://server.example.com/token\",\n}\n\n// Create a key-pair to be used for signing\nprivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)\nif err != nil {\n  ...\n}\n\n// Create a signed proof string\nproofString, err := dpop.Create(jwt.SigningMethodES256, claims, privateKey)\nif err != nil {\n  ...\n}\n\n// Send the proof string in the 'DPoP' header to the server\n```\n\n### Note on HMAC\n\nAlthough this package can in theory support symmetric keys the [DPoP draft does not allow private keys](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-dpop#name-dpop-proof-jwt-syntax) to be sent in the proof `jwk` header. As a symmetric key has no public key cryptography it can not be included in the proof, hence why it is unsupported.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faxiscommunications%2Fgo-dpop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faxiscommunications%2Fgo-dpop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faxiscommunications%2Fgo-dpop/lists"}