1package oidc_test
2
3import (
4	"context"
5	"encoding/json"
6	"fmt"
7	"net/http"
8	"time"
9
10	"github.com/hashicorp/cap/oidc"
11)
12
13func Example() {
14	ctx := context.Background()
15	// Create a new Config
16	pc, err := oidc.NewConfig(
17		"http://your-issuer.com/",
18		"your_client_id",
19		"your_client_secret",
20		[]oidc.Alg{oidc.RS256},
21		[]string{"http://your_redirect_url"},
22	)
23	if err != nil {
24		// handle error
25	}
26
27	// Create a provider
28	p, err := oidc.NewProvider(pc)
29	if err != nil {
30		// handle error
31	}
32	defer p.Done()
33
34	// Create a Request for a user's authentication attempt that will use the
35	// authorization code flow.  (See NewRequest(...) using the WithPKCE and
36	// WithImplicit options for creating a Request that uses those flows.)
37	oidcRequest, err := oidc.NewRequest(2*time.Minute, "http://your_redirect_url/callback")
38	if err != nil {
39		// handle error
40	}
41
42	// Create an auth URL
43	authURL, err := p.AuthURL(ctx, oidcRequest)
44	if err != nil {
45		// handle error
46	}
47	fmt.Println("open url to kick-off authentication: ", authURL)
48
49	// Create a http.Handler for OIDC authentication response redirects
50	callbackHandler := func(w http.ResponseWriter, r *http.Request) {
51		// Exchange a successful authentication's authorization code and
52		// authorization state (received in a callback) for a verified Token.
53		t, err := p.Exchange(ctx, oidcRequest, r.FormValue("state"), r.FormValue("code"))
54		if err != nil {
55			// handle error
56		}
57		var claims map[string]interface{}
58		if err := t.IDToken().Claims(&claims); err != nil {
59			// handle error
60		}
61
62		// Get the user's claims via the provider's UserInfo endpoint
63		var infoClaims map[string]interface{}
64		err = p.UserInfo(ctx, t.StaticTokenSource(), claims["sub"].(string), &infoClaims)
65		if err != nil {
66			// handle error
67		}
68		resp := struct {
69			IDTokenClaims  map[string]interface{}
70			UserInfoClaims map[string]interface{}
71		}{claims, infoClaims}
72		enc := json.NewEncoder(w)
73		if err := enc.Encode(resp); err != nil {
74			// handle error
75		}
76	}
77	http.HandleFunc("/callback", callbackHandler)
78}
79
80func ExampleNewConfig() {
81	// Create a new Config
82	pc, err := oidc.NewConfig(
83		"http://your_issuer/",
84		"your_client_id",
85		"your_client_secret",
86		[]oidc.Alg{oidc.RS256},
87		[]string{"http://your_redirect_url/callback"},
88	)
89	if err != nil {
90		// handle error
91	}
92	fmt.Println(pc)
93
94	// Output:
95	// &{your_client_id [REDACTED: client secret] [openid] http://your_issuer/ [RS256] [http://your_redirect_url/callback] []  <nil>}
96}
97
98func ExampleNewProvider() {
99	// Create a new Config
100	pc, err := oidc.NewConfig(
101		"http://your_issuer/",
102		"your_client_id",
103		"your_client_secret",
104		[]oidc.Alg{oidc.RS256},
105		[]string{"http://your_redirect_url/callback"},
106	)
107	if err != nil {
108		// handle error
109	}
110
111	// Create a provider
112	p, err := oidc.NewProvider(pc)
113	if err != nil {
114		// handle error
115	}
116	defer p.Done()
117}
118
119func ExampleProvider_AuthURL() {
120	ctx := context.Background()
121	// Create a new Config
122	pc, err := oidc.NewConfig(
123		"http://your_issuer/",
124		"your_client_id",
125		"your_client_secret",
126		[]oidc.Alg{oidc.RS256},
127		[]string{"http://your_redirect_url/callback"},
128	)
129	if err != nil {
130		// handle error
131	}
132
133	// Create a provider
134	p, err := oidc.NewProvider(pc)
135	if err != nil {
136		// handle error
137	}
138	defer p.Done()
139
140	// Create a Request for a user's authentication attempt that will use the
141	// authorization code flow.  (See NewRequest(...) using the WithPKCE and
142	// WithImplicit options for creating a Request that uses those flows.)
143	oidcRequest, err := oidc.NewRequest(2*time.Minute, "http://your_redirect_url/callback")
144	if err != nil {
145		// handle error
146	}
147
148	// Create an auth URL
149	authURL, err := p.AuthURL(ctx, oidcRequest)
150	if err != nil {
151		// handle error
152	}
153	fmt.Println("open url to kick-off authentication: ", authURL)
154}
155
156func ExampleProvider_Exchange() {
157	ctx := context.Background()
158
159	// Create a new Config
160	pc, err := oidc.NewConfig(
161		"http://your-issuer.com/",
162		"your_client_id",
163		"your_client_secret",
164		[]oidc.Alg{oidc.RS256},
165		[]string{"http://your_redirect_url"},
166	)
167	if err != nil {
168		// handle error
169	}
170
171	// Create a provider
172	p, err := oidc.NewProvider(pc)
173	if err != nil {
174		// handle error
175	}
176	defer p.Done()
177
178	// Create a Request for a user's authentication attempt that will use the
179	// authorization code flow.  (See NewRequest(...) using the WithPKCE and
180	// WithImplicit options for creating a Request that uses those flows.)
181	oidcRequest, err := oidc.NewRequest(2*time.Minute, "http://your_redirect_url/callback")
182	if err != nil {
183		// handle error
184	}
185
186	// Create an auth URL
187	authURL, err := p.AuthURL(ctx, oidcRequest)
188	if err != nil {
189		// handle error
190	}
191	fmt.Println("open url to kick-off authentication: ", authURL)
192
193	// Create a http.Handler for OIDC authentication response redirects
194	callbackHandler := func(w http.ResponseWriter, r *http.Request) {
195		// Exchange a successful authentication's authorization code and
196		// authorization state (received in a callback) for a verified Token.
197		t, err := p.Exchange(ctx, oidcRequest, r.FormValue("state"), r.FormValue("code"))
198		if err != nil {
199			// handle error
200		}
201		var claims map[string]interface{}
202		if err := t.IDToken().Claims(&claims); err != nil {
203			// handle error
204		}
205
206		// Get the user's claims via the provider's UserInfo endpoint
207		var infoClaims map[string]interface{}
208		err = p.UserInfo(ctx, t.StaticTokenSource(), claims["sub"].(string), &infoClaims)
209		if err != nil {
210			// handle error
211		}
212		resp := struct {
213			IDTokenClaims  map[string]interface{}
214			UserInfoClaims map[string]interface{}
215		}{claims, infoClaims}
216		enc := json.NewEncoder(w)
217		if err := enc.Encode(resp); err != nil {
218			// handle error
219		}
220	}
221	http.HandleFunc("/callback", callbackHandler)
222}
223
224func ExampleProvider_UserInfo() {
225	ctx := context.Background()
226
227	// Create a new Config
228	pc, err := oidc.NewConfig(
229		"http://your-issuer.com/",
230		"your_client_id",
231		"your_client_secret",
232		[]oidc.Alg{oidc.RS256},
233		[]string{"http://your_redirect_url"},
234	)
235	if err != nil {
236		// handle error
237	}
238
239	// Create a provider
240	p, err := oidc.NewProvider(pc)
241	if err != nil {
242		// handle error
243	}
244	defer p.Done()
245
246	// Create a Request for a user's authentication attempt that will use the
247	// authorization code flow.  (See NewRequest(...) using the WithPKCE and
248	// WithImplicit options for creating a Request that uses those flows.)
249	oidcRequest, err := oidc.NewRequest(2*time.Minute, "http://your_redirect_url/callback")
250	if err != nil {
251		// handle error
252	}
253
254	// Create an auth URL
255	authURL, err := p.AuthURL(ctx, oidcRequest)
256	if err != nil {
257		// handle error
258	}
259	fmt.Println("open url to kick-off authentication: ", authURL)
260
261	// Create a http.Handler for OIDC authentication response redirects
262	callbackHandler := func(w http.ResponseWriter, r *http.Request) {
263		// Exchange a successful authentication's authorization code and
264		// authorization state (received in a callback) for a verified Token.
265		t, err := p.Exchange(ctx, oidcRequest, r.FormValue("state"), r.FormValue("code"))
266		if err != nil {
267			// handle error
268		}
269		var claims map[string]interface{}
270		if err := t.IDToken().Claims(&claims); err != nil {
271			// handle error
272		}
273
274		// Get the user's claims via the provider's UserInfo endpoint
275		var infoClaims map[string]interface{}
276		err = p.UserInfo(ctx, t.StaticTokenSource(), claims["sub"].(string), &infoClaims)
277		if err != nil {
278			// handle error
279		}
280		resp := struct {
281			IDTokenClaims  map[string]interface{}
282			UserInfoClaims map[string]interface{}
283		}{claims, infoClaims}
284		enc := json.NewEncoder(w)
285		if err := enc.Encode(resp); err != nil {
286			// handle error
287		}
288	}
289	http.HandleFunc("/callback", callbackHandler)
290}
291
292func ExampleNewRequest() {
293	// Create a Request for a user's authentication attempt that will use the
294	// authorization code flow.  (See NewRequest(...) using the WithPKCE and
295	// WithImplicit options for creating a Request that uses those flows.)
296	ttl := 2 * time.Minute
297	oidcRequest, err := oidc.NewRequest(ttl, "http://your_redirect_url/callback")
298	if err != nil {
299		// handle error
300	}
301	fmt.Println(oidcRequest)
302
303	// Create a Request for a user's authentication attempt that will use the
304	// authorization code flow with PKCE
305	v, err := oidc.NewCodeVerifier()
306	if err != nil {
307		// handle error
308	}
309	oidcRequest, err = oidc.NewRequest(ttl, "http://your_redirect_url/callback", oidc.WithPKCE(v))
310	if err != nil {
311		// handle error
312	}
313	fmt.Println(oidcRequest)
314
315	// Create a Request for a user's authentication attempt that will use the
316	// implicit flow.
317	oidcRequest, err = oidc.NewRequest(ttl, "http://your_redirect_url/callback", oidc.WithImplicitFlow())
318	if err != nil {
319		// handle error
320	}
321	fmt.Println(oidcRequest)
322
323	// Create a Request for a user's authentication attempt that will use the
324	// authorization code flow and require a auth_time with a max_age of 0
325	// seconds.
326	ttl = 2 * time.Minute
327	oidcRequest, err = oidc.NewRequest(ttl, "http://your_redirect_url/callback", oidc.WithMaxAge(0))
328	if err != nil {
329		// handle error
330	}
331	fmt.Println(oidcRequest)
332}
333