/*
Package oidc implements OpenID Connect client logic for the golang.org/x/oauth2 package.

	provider, err := oidc.NewProvider(ctx, "https://accounts.example.com")
	if err != nil {
		return err
	}

	// Configure an OpenID Connect aware OAuth2 client.
	oauth2Config := oauth2.Config{
		ClientID:     clientID,
		ClientSecret: clientSecret,
		RedirectURL:  redirectURL,
		Endpoint:     provider.Endpoint(),
		Scopes:       []string{oidc.ScopeOpenID, "profile", "email"},
	}

OAuth2 redirects are unchanged.

	func handleRedirect(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, oauth2Config.AuthCodeURL(state), http.StatusFound)
	})

For callbacks the provider can be used to query for user information such as email.

	func handleOAuth2Callback(w http.ResponseWriter, r *http.Request) {
		// Verify state...

		oauth2Token, err := oauth2Config.Exchange(ctx, r.URL.Query().Get("code"))
		if err != nil {
			http.Error(w, "Failed to exchange token: "+err.Error(), http.StatusInternalServerError)
			return
		}

		userinfo, err := provider.UserInfo(ctx, oauth2.StaticTokenSource(oauth2Token))
		if err != nil {
			http.Error(w, "Failed to get userinfo: "+err.Error(), http.StatusInternalServerError)
			return
		}

		// ...
	})

The provider also has the ability to verify ID Tokens.

	verifier := provider.NewVerifier(ctx)

The returned verifier can be used to perform basic validation on ID Token issued by the provider,
including verifying the JWT signature. It then returns the payload.

	func handleOAuth2Callback(w http.ResponseWriter, r *http.Request) {
		// Verify state...

		oauth2Token, err := oauth2Config.Exchange(ctx, r.URL.Query().Get("code"))
		if err != nil {
			http.Error(w, "Failed to exchange token: "+err.Error(), http.StatusInternalServerError)
			return
		}

		// Extract the ID Token from oauth2 token.
		rawIDToken, ok := oauth2Token.Extra("id_token").(string)
		if !ok {
			http.Error(w, "No ID Token found", http.StatusInternalServerError)
			return
		}

		// Verify that the ID Token is signed by the provider.
		idToken, err := verifier.Verify(rawIDToken)
		if err != nil {
			http.Error(w, "Failed to verify ID Token: "+err.Error(), http.StatusInternalServerError)
			return
		}

		// Unmarshal ID Token for expected custom claims.
		var claims struct {
			Email         string `json:"email"`
			EmailVerified bool   `json:"email_verified"`
		}
		if err := idToken.Claims(&claims); err != nil {
			http.Error(w, "Failed to unmarshal ID Token custom claims: "+err.Error(), http.StatusInternalServerError)
			return
		}

		// ...
	})

ID Token nonces are supported.

First, provide a nonce source for nonce validation. This will then be used to wrap the existing
provider ID Token verifier.

	// A verifier which boths verifies the ID Token signature and nonce.
	nonceEnabledVerifier := provider.NewVerifier(ctx, oidc.VerifyNonce(nonceSource))

For the redirect provide a nonce auth code option. This will be placed as a URL parameter during
the client redirect.

	func handleRedirect(w http.ResponseWriter, r *http.Request) {
		nonce, err := newNonce()
		if err != nil {
			// ...
		}
		// Provide a nonce for the OpenID Connect ID Token.
		http.Redirect(w, r, oauth2Config.AuthCodeURL(state, oidc.Nonce(nonce)), http.StatusFound)
	})

The nonce enabled verifier can then be used to verify the nonce while unpacking the ID Token.

	func handleOAuth2Callback(w http.ResponseWriter, r *http.Request) {
		// Verify state...

		oauth2Token, err := oauth2Config.Exchange(ctx, r.URL.Query().Get("code"))
		if err != nil {
			http.Error(w, "Failed to exchange token: "+err.Error(), http.StatusInternalServerError)
			return
		}

		// Extract the ID Token from oauth2 token.
		rawIDToken, ok := oauth2Token.Extra("id_token").(string)
		if !ok {
			http.Error(w, "No ID Token found", http.StatusInternalServerError)
			return
		}

		// Verify that the ID Token is signed by the provider and verify the nonce.
		idToken, err := nonceEnabledVerifier.Verify(rawIDToken)
		if err != nil {
			http.Error(w, "Failed to verify ID Token: "+err.Error(), http.StatusInternalServerError)
			return
		}

		// Continue as above...
	})

This package uses contexts to derive HTTP clients in the same way as the oauth2 package. To configure
a custom client, use the oauth2 packages HTTPClient context key when constructing the context.

	myClient := &http.Client{}

	myCtx := context.WithValue(parentCtx, oauth2.HTTPClient, myClient)

	// NewProvider will use myClient to make the request.
	provider, err := oidc.NewProvider(myCtx, "https://accounts.example.com")
*/
package oidc