1- // Package oidc implements OpenID Connect client logic for the golang.org/x/oauth2 package.
21package oidc
32
43import (
@@ -92,7 +91,24 @@ func doRequest(ctx context.Context, req *http.Request) (*http.Response, error) {
9291 return client .Do (req .WithContext (ctx ))
9392}
9493
95- // Provider represents an OpenID Connect server's configuration.
94+ // Provider represents an OpenID Connect server's configuration, fetched from
95+ // the discovery document.
96+ //
97+ // To access fields in the discovery document that aren't exposed directly
98+ // through this package's API, use the [Provider.Claims] method. For example, to
99+ // access the registration or end session endpoints:
100+ //
101+ // p, err := oidc.NewProvider(ctx, "https://issuer.example.com")
102+ // if err != nil {
103+ // // ...
104+ // }
105+ // var metadata struct {
106+ // EndSessionEndpoint string `json:"end_session_endpoint"`
107+ // RegistrationEndpoint string `json:"registration_endpoint"`
108+ // }
109+ // if err := p.Claims(&metadata); err != nil {
110+ // // ...
111+ // }
96112type Provider struct {
97113 issuer string
98114 authURL string
@@ -213,6 +229,8 @@ type ProviderConfig struct {
213229//
214230// The provided context is only used for [http.Client] configuration through
215231// [ClientContext], not cancelation.
232+ //
233+ // For providers that implement discovery, use [NewProvider] instead.
216234func (p * ProviderConfig ) NewProvider (ctx context.Context ) * Provider {
217235 return & Provider {
218236 issuer : p .IssuerURL ,
@@ -231,7 +249,7 @@ func (p *ProviderConfig) NewProvider(ctx context.Context) *Provider {
231249// or "https://login.salesforce.com".
232250//
233251// OpenID Connect providers that don't implement discovery or host the discovery
234- // document at a non-spec complaint path (such as requiring a URL parameter),
252+ // document at a non-spec compliant path (such as requiring a URL parameter),
235253// should use [ProviderConfig] instead.
236254//
237255// See: https://openid.net/specs/openid-connect-discovery-1_0.html
@@ -348,6 +366,44 @@ func (u *UserInfo) Claims(v any) error {
348366}
349367
350368// UserInfo uses the token source to query the provider's user info endpoint.
369+ //
370+ // It's fewer round trips and better supported to validate the ID Token with
371+ // [Provider.Verifier], rather than using the UserInfo endpoint. The ID Token
372+ // contains all information [UserInfo] provides:
373+ //
374+ // p, err := oidc.NewProvider(ctx, "https://issuer.example.com")
375+ // if err != nil {
376+ // // ...
377+ // }
378+ // config := &oidc.Config{
379+ // ClientID: clientID,
380+ // }
381+ // v := p.Verifier(config)
382+ // http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
383+ // oauth2Token, err := config.Exchange(ctx, r.URL.Query().Get("code"))
384+ // if err != nil {
385+ // // ...
386+ // }
387+ // rawIDToken, ok := oauth2Token.Extra("id_token").(string)
388+ // if !ok {
389+ // // ...
390+ // }
391+ // idToken, err := verifier.Verify(ctx, rawIDToken)
392+ // if err != nil {
393+ // // ...
394+ // }
395+ // // https://openid.net/specs/openid-connect-core-1_0.html#Claims
396+ // var claims struct {
397+ // Email string `json:"email"`
398+ // EmailVerified bool `json:"email_verified"`
399+ // Name string `json:"name"`
400+ // Picture string `json:"picture"`
401+ // }
402+ // if err := idToken.Claims(&claims); err != nil {
403+ // // ...
404+ // }
405+ // // Use claims...
406+ // })
351407func (p * Provider ) UserInfo (ctx context.Context , tokenSource oauth2.TokenSource ) (* UserInfo , error ) {
352408 if p .userInfoURL == "" {
353409 return nil , errors .New ("oidc: user info endpoint is not supported by this provider" )
@@ -425,15 +481,15 @@ type IDToken struct {
425481 // A unique string which identifies the end user.
426482 Subject string
427483
428- // Expiry of the token. Ths package will not process tokens that have
484+ // Expiry of the token. This package will not process tokens that have
429485 // expired unless that validation is explicitly turned off.
430486 Expiry time.Time
431487 // When the token was issued by the provider.
432488 IssuedAt time.Time
433489
434490 // Initial nonce provided during the authentication redirect.
435491 //
436- // This package does NOT provided verification on the value of this field
492+ // This package does NOT provide verification on the value of this field
437493 // and it's the user's responsibility to ensure it contains a valid value.
438494 Nonce string
439495
@@ -472,8 +528,8 @@ func (i *IDToken) Claims(v any) error {
472528 return json .Unmarshal (i .claims , v )
473529}
474530
475- // VerifyAccessToken verifies that the hash of the access token that corresponds to the iD token
476- // matches the hash in the id token. It returns an error if the hashes don't match.
531+ // VerifyAccessToken verifies that the hash of the access token that corresponds to the ID token
532+ // matches the hash in the ID token. It returns an error if the hashes don't match.
477533// It is the caller's responsibility to ensure that the optional access token hash is present for the ID token
478534// before calling this method. See https://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken
479535func (i * IDToken ) VerifyAccessToken (accessToken string ) error {
0 commit comments