1# oidc 2[![Go Reference](https://pkg.go.dev/badge/github.com/hashicorp/cap/oidc.svg)](https://pkg.go.dev/github.com/hashicorp/cap/oidc) 3 4oidc is a package for writing clients that integrate with OIDC Providers using 5OIDC flows. 6 7Primary types provided by the package: 8 9* `Request`: represents one OIDC authentication flow for a user. It contains the 10 data needed to uniquely represent that one-time flow across the multiple 11 interactions needed to complete the OIDC flow the user is attempting. All 12 Requests contain an expiration for the user's OIDC flow. 13 14* `Token`: represents an OIDC id_token, as well as an Oauth2 access_token and 15 refresh_token (including the the access_token expiry) 16 17* `Config`: provides the configuration for a typical 3-legged OIDC 18 authorization code flow (for example: client ID/Secret, redirectURL, supported 19 signing algorithms, additional scopes requested, etc) 20 21* `Provider`: provides integration with an OIDC provider. 22 The provider provides capabilities like: generating an auth URL, exchanging 23 codes for tokens, verifying tokens, making user info requests, etc. 24 25* `Alg`: represents asymmetric signing algorithms 26 27* `Error`: provides an error and provides the ability to specify an error code, 28 operation that raised the error, the kind of error, and any wrapped error 29 30#### [oidc.callback](callback/) 31[![Go Reference](https://pkg.go.dev/badge/github.com/hashicorp/cap/oidc/callback.svg)](https://pkg.go.dev/github.com/hashicorp/cap/oidc/callback) 32 33The callback package includes handlers (http.HandlerFunc) which can be used 34for the callback leg an OIDC flow. Callback handlers for both the authorization 35code flow (with optional PKCE) and the implicit flow are provided. 36 37<hr> 38 39### Examples: 40 41* [CLI example](examples/cli/) which implements an OIDC 42 user authentication CLI. 43 44* [SPA example](examples/spa) which implements an OIDC user 45 authentication SPA (single page app). 46 47<hr> 48 49Example of a provider using an authorization code flow: 50 51```go 52// Create a new provider config 53pc, err := oidc.NewConfig( 54 "http://your-issuer.com/", 55 "your_client_id", 56 "your_client_secret", 57 []oidc.Alg{oidc.RS256}, 58 []string{"http://your_redirect_url"}, 59) 60if err != nil { 61 // handle error 62} 63 64// Create a provider 65p, err := oidc.NewProvider(pc) 66if err != nil { 67 // handle error 68} 69defer p.Done() 70 71 72// Create a Request for a user's authentication attempt that will use the 73// authorization code flow. (See NewRequest(...) using the WithPKCE and 74// WithImplicit options for creating a Request that uses those flows.) 75oidcRequest, err := oidc.NewRequest(2 * time.Minute, "http://your_redirect_url/callback") 76if err != nil { 77 // handle error 78} 79 80// Create an auth URL 81authURL, err := p.AuthURL(context.Background(), oidcRequest) 82if err != nil { 83 // handle error 84} 85fmt.Println("open url to kick-off authentication: ", authURL) 86``` 87 88Create a http.Handler for OIDC authentication response redirects. 89 90```go 91func NewHandler(ctx context.Context, p *oidc.Provider, rw callback.RequestReader) (http.HandlerFunc, error) 92 if p == nil { 93 // handle error 94 } 95 if rw == nil { 96 // handle error 97 } 98 return func(w http.ResponseWriter, r *http.Request) { 99 oidcRequest, err := rw.Read(ctx, req.FormValue("state")) 100 if err != nil { 101 // handle error 102 } 103 // Exchange(...) will verify the tokens before returning. 104 token, err := p.Exchange(ctx, oidcRequest, req.FormValue("state"), req.FormValue("code")) 105 if err != nil { 106 // handle error 107 } 108 var claims map[string]interface{} 109 if err := t.IDToken().Claims(&claims); err != nil { 110 // handle error 111 } 112 113 // Get the user's claims via the provider's UserInfo endpoint 114 var infoClaims map[string]interface{} 115 err = p.UserInfo(ctx, token.StaticTokenSource(), claims["sub"].(string), &infoClaims) 116 if err != nil { 117 // handle error 118 } 119 resp := struct { 120 IDTokenClaims map[string]interface{} 121 UserInfoClaims map[string]interface{} 122 }{claims, infoClaims} 123 enc := json.NewEncoder(w) 124 if err := enc.Encode(resp); err != nil { 125 // handle error 126 } 127 } 128} 129``` 130 131 132