README.md
1# cap
2
3`cap` (collection of authentication packages) provides a collection of related
4packages which enable support for OIDC, JWT Verification and Distributed Claims.
5
6**Please note**: We take security and our users' trust very seriously. If you
7believe you have found a security issue, please [responsibly
8disclose](https://www.hashicorp.com/security#vulnerability-reporting) by
9contacting us at security@hashicorp.com.
10
11## Contributing
12
13Thank you for your interest in contributing! Please refer to
14[CONTRIBUTING.md](https://github.com/hashicorp/cap/blob/main/CONTRIBUTING.md)
15for guidance.
16
17<hr>
18
19### [`oidc package`](./oidc)
20[![Go Reference](https://pkg.go.dev/badge/github.com/hashicorp/cap/oidc.svg)](https://pkg.go.dev/github.com/hashicorp/cap/oidc)
21
22 A package for writing clients that integrate with OIDC Providers. Primary types provided by the
23 package are:
24 1. Request
25 2. Token
26 3. Config
27 4. Provider
28
29The package also provides callbacks (in the form of http.HandlerFunc) for
30handling OIDC provider responses to authorization code flow (with optional PKCE)
31and implicit flow authentication attempts.
32<hr>
33
34Example of a provider using an authorization code flow:
35```go
36// Create a new provider config
37pc, err := oidc.NewConfig(
38 "http://your-issuer.com/",
39 "your_client_id",
40 "your_client_secret",
41 []oidc.Alg{oidc.RS256},
42 []string{"https://your_redirect_url"},
43)
44if err != nil {
45 // handle error
46}
47
48// Create a provider
49p, err := oidc.NewProvider(pc)
50if err != nil {
51 // handle error
52}
53defer p.Done()
54
55
56// Create a Request for a user's authorization code flow authentication attempt,
57// with a 2 min timeout for completion.
58oidcRequest, err := oidc.NewRequest(2 * time.Minute, "https://your_redirect_url")
59if err != nil {
60 // handle error
61}
62
63
64// Create an auth URL
65authURL, err := p.AuthURL(ctx, oidcRequest)
66if err != nil {
67 // handle error
68}
69fmt.Println("open url to kick-off authentication: ", authURL)
70```
71
72Create a http.Handler for OIDC authentication response redirects.
73```go
74func NewHandler(ctx context.Context, p *oidc.Provider, r callback.RequestReader) (http.HandlerFunc, error)
75 if p == nil {
76 // handle error
77 }
78 if rw == nil {
79 // handle error
80 }
81 return func(w http.ResponseWriter, req *http.Request) {
82 oidcRequest, err := rw.Read(ctx, req.FormValue("state"))
83 if err != nil {
84 // handle error
85 }
86 // Exchange(...) will verify the tokens before returning.
87 token, err := p.Exchange(ctx, oidcRequest, req.FormValue("state"), req.FormValue("code"))
88 if err != nil {
89 // handle error
90 }
91 var claims map[string]interface{}
92 if err := token.IDToken().Claims(&claims); err != nil {
93 // handle error
94 }
95
96 // Get the user's claims via the provider's UserInfo endpoint
97 var infoClaims map[string]interface{}
98 err = p.UserInfo(ctx, token.StaticTokenSource(), claims["sub"].(string), &infoClaims)
99 if err != nil {
100 // handle error
101 }
102 resp := struct {
103 IDTokenClaims map[string]interface{}
104 UserInfoClaims map[string]interface{}
105 }{claims, infoClaims}
106 enc := json.NewEncoder(w)
107 if err := enc.Encode(resp); err != nil {
108 // handle error
109 }
110 }
111}
112```
113
114### [`jwt package`](./jwt)
115[![Go Reference](https://pkg.go.dev/badge/github.com/hashicorp/cap/jwt.svg)](https://pkg.go.dev/github.com/hashicorp/cap/jwt)
116
117Package jwt provides signature verification and claims set validation for JSON Web Tokens (JWT)
118of the JSON Web Signature (JWS) form.
119
120JWT claims set validation provided by the package includes the option to validate
121all registered claim names defined in [rfc7519#section-4.1](https://tools.ietf.org/html/rfc7519#section-4.1).
122
123JOSE header validation provided by the the package includes the option to validate the "alg"
124(Algorithm) Header Parameter defined in [rfc7515#section-4.1](https://tools.ietf.org/html/rfc7515#section-4.1).
125
126JWT signature verification is supported by providing keys from the following sources:
127
128- JSON Web Key Set (JWKS) URL
129- OIDC Discovery mechanism
130- Local public keys
131
132JWT signature verification supports the following asymmetric algorithms defined in
133[rfc7518.html#section-3.1](https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1):
134
135| Identifier | Signing Algorithm |
136| -------------- | :---------------- |
137| RS256 | RSASSA-PKCS1-v1_5 using SHA-256 |
138| RS384 | RSASSA-PKCS1-v1_5 using SHA-384 |
139| RS512 | RSASSA-PKCS1-v1_5 using SHA-512 |
140| ES256 | ECDSA using P-256 and SHA-256 |
141| ES384 | ECDSA using P-384 and SHA-384 |
142| ES512 | ECDSA using P-521 and SHA-512 |
143| PS256 | RSASSA-PSS using SHA-256 and MGF1 with SHA-256 |
144| PS384 | RSASSA-PSS using SHA-384 and MGF1 with SHA-384 |
145| PS512 | RSASSA-PSS using SHA-512 and MGF1 with SHA-512 |
146| EdDSA | Ed25519 using SHA-512 |
147
148<hr>
149
150Example usage of JWT signature verification and claims set validation using keys from a JWKS URL:
151
152```go
153ctx := context.Background()
154
155keySet, err := jwt.NewJSONWebKeySet(ctx, "your_jwks_url", "your_jwks_ca_pem")
156if err != nil {
157 log.Fatal(err)
158}
159
160validator, err := jwt.NewValidator(keySet)
161if err != nil {
162 log.Fatal(err)
163}
164
165expected := jwt.Expected{
166 Issuer: "your_expected_issuer",
167 Subject: "your_expected_subject",
168 ID: "your_expected_jwt_id",
169 Audiences: []string{"your_expected_audiences"},
170 SigningAlgorithms: []jwt.Alg{jwt.RS256},
171}
172
173token := "header.payload.signature"
174claims, err := validator.Validate(ctx, token, expected)
175if err != nil {
176 log.Fatal(err)
177}
178```
179
180For additional documentation and usage examples, see [jwt/README.md](./jwt).
181