Repository: coreos/dex
Pull request #840 (2017-03-08 18:34:55)

*: update go-oidc and use standard library's context package


Patch:
diff --git a/Documentation/integrations.md b/Documentation/integrations.md
deleted file mode 100644
index 071dc0a7..00000000
--- a/Documentation/integrations.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# Integrations
-This document tracks the libraries and tools that are compatible with dex. [Join the community](https://github.com/coreos/dex/), and help us keep the list up-to-date.
-
-## Tools
-
-## Projects with a dex dependency
diff --git a/Documentation/production-users.md b/Documentation/production-users.md
deleted file mode 100644
index 55a74c9a..00000000
--- a/Documentation/production-users.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Production users
-
-This document tracks people and use cases for dex in production. [Join the community](https://github.com/coreos/dex/), and help us keep the list up-to-date.
\ No newline at end of file
diff --git a/cmd/dex/serve.go b/cmd/dex/serve.go
index 6c708c4e..08d9fdb0 100644
--- a/cmd/dex/serve.go
+++ b/cmd/dex/serve.go
@@ -1,6 +1,7 @@
 package main
 
 import (
+	"context"
 	"crypto/tls"
 	"crypto/x509"
 	"errors"
@@ -15,7 +16,6 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/ghodss/yaml"
 	"github.com/spf13/cobra"
-	"golang.org/x/net/context"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials"
 
diff --git a/cmd/example-app/main.go b/cmd/example-app/main.go
index 3ec34e38..4da34b9a 100644
--- a/cmd/example-app/main.go
+++ b/cmd/example-app/main.go
@@ -2,6 +2,7 @@ package main
 
 import (
 	"bytes"
+	"context"
 	"crypto/tls"
 	"crypto/x509"
 	"encoding/json"
@@ -19,7 +20,6 @@ import (
 
 	"github.com/coreos/go-oidc"
 	"github.com/spf13/cobra"
-	"golang.org/x/net/context"
 	"golang.org/x/oauth2"
 )
 
@@ -175,7 +175,7 @@ func cmd() *cobra.Command {
 			}
 
 			a.provider = provider
-			a.verifier = provider.Verifier(oidc.VerifyAudience(a.clientID))
+			a.verifier = provider.Verifier(&oidc.Config{ClientID: a.clientID})
 
 			http.HandleFunc("/", a.handleIndex)
 			http.HandleFunc("/login", a.handleLogin)
diff --git a/connector/connector.go b/connector/connector.go
index c92d7589..fde38a24 100644
--- a/connector/connector.go
+++ b/connector/connector.go
@@ -2,9 +2,8 @@
 package connector
 
 import (
+	"context"
 	"net/http"
-
-	"golang.org/x/net/context"
 )
 
 // Connector is a mechanism for federating login to a remote identity service.
diff --git a/connector/github/github.go b/connector/github/github.go
index f6dbdfee..49dc3bb3 100644
--- a/connector/github/github.go
+++ b/connector/github/github.go
@@ -2,6 +2,7 @@
 package github
 
 import (
+	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -10,7 +11,6 @@ import (
 	"regexp"
 	"strconv"
 
-	"golang.org/x/net/context"
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2/github"
 
diff --git a/connector/gitlab/gitlab.go b/connector/gitlab/gitlab.go
index 0fcc3d26..b0f10cf1 100644
--- a/connector/gitlab/gitlab.go
+++ b/connector/gitlab/gitlab.go
@@ -2,6 +2,7 @@
 package gitlab
 
 import (
+	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -12,7 +13,6 @@ import (
 
 	"github.com/Sirupsen/logrus"
 	"github.com/coreos/dex/connector"
-	"golang.org/x/net/context"
 	"golang.org/x/oauth2"
 )
 
diff --git a/connector/ldap/ldap.go b/connector/ldap/ldap.go
index c5e45d37..df3d4c9d 100644
--- a/connector/ldap/ldap.go
+++ b/connector/ldap/ldap.go
@@ -2,6 +2,7 @@
 package ldap
 
 import (
+	"context"
 	"crypto/tls"
 	"crypto/x509"
 	"encoding/json"
@@ -9,7 +10,6 @@ import (
 	"io/ioutil"
 	"net"
 
-	"golang.org/x/net/context"
 	"gopkg.in/ldap.v2"
 
 	"github.com/Sirupsen/logrus"
diff --git a/connector/oidc/oidc.go b/connector/oidc/oidc.go
index 6a8b6f98..728bdf6a 100644
--- a/connector/oidc/oidc.go
+++ b/connector/oidc/oidc.go
@@ -2,13 +2,13 @@
 package oidc
 
 import (
+	"context"
 	"errors"
 	"fmt"
 	"net/http"
 
 	"github.com/Sirupsen/logrus"
 	"github.com/coreos/go-oidc"
-	"golang.org/x/net/context"
 	"golang.org/x/oauth2"
 
 	"github.com/coreos/dex/connector"
@@ -53,10 +53,10 @@ func (c *Config) Open(logger logrus.FieldLogger) (conn connector.Connector, err
 			RedirectURL:  c.RedirectURI,
 		},
 		verifier: provider.Verifier(
-			oidc.VerifyExpiry(),
-			oidc.VerifyAudience(clientID),
+			&oidc.Config{ClientID: clientID},
 		),
 		logger: logger,
+		cancel: cancel,
 	}, nil
 }
 
diff --git a/examples/grpc-client/README.md b/examples/grpc-client/README.md
index bd39219b..0c1f82c1 100644
--- a/examples/grpc-client/README.md
+++ b/examples/grpc-client/README.md
@@ -55,7 +55,7 @@ Running the gRPC client will cause the following API calls to be made to the ser
 Run the following command to destroy all the credentials files that were created by the `cert-gen` script:
 
 ```
-./examples/grpc-client/cert-destroy
+./examples/grpc-client/cert-destory
 ```
 [api-proto]: ../../api/api.proto
 [client]: client.go
diff --git a/examples/grpc-client/client.go b/examples/grpc-client/client.go
index 06ea97fa..073f1fb1 100644
--- a/examples/grpc-client/client.go
+++ b/examples/grpc-client/client.go
@@ -49,7 +49,7 @@ func main() {
 	flag.Parse()
 
 	if *clientCrt == "" || *caCrt == "" || *clientKey == "" {
-		log.Fatal("Please provide CA & client certificates and client key. Usage: ./client --ca-crt=<path ca.crt> --client-crt=<path client.crt> --client-key=<path client key>")
+		log.Fatal("Please provide CA & client certificates and client key. Usage: ./client -ca_crt=<path ca.crt> -client_crt=<path client.crt> -client_key=<path client key>")
 	}
 
 	client, err := newDexClient("127.0.0.1:5557", *caCrt, *clientCrt, *clientKey)
diff --git a/glide.lock b/glide.lock
index 3edb6fb3..97eb92d5 100644
--- a/glide.lock
+++ b/glide.lock
@@ -1,5 +1,5 @@
-hash: 1207c251a7dab3b824746d66219beabc40f0b1d3c08ed90ac50f5bbdb8872631
-updated: 2017-01-25T20:32:43.599648533+01:00
+hash: fbef1f81a0f86f519714bbe568692a92709c446ef487a3fa9875e58f86e14430
+updated: 2017-03-08T10:31:06.364335442-08:00
 imports:
 - name: github.com/beevik/etree
   version: 4cd0dd976db869f817248477718071a28e978df0
@@ -8,7 +8,7 @@ imports:
   subpackages:
   - crdb
 - name: github.com/coreos/go-oidc
-  version: 2b5d73091ea4b7ddb15e3ac00077f153120b5b61
+  version: be73733bb8cc830d0205609b95d125215f8e9c70
 - name: github.com/ghodss/yaml
   version: bea76d6a4713e18b7f5321a2b020738552def3ea
 - name: github.com/go-sql-driver/mysql
@@ -62,7 +62,6 @@ imports:
   version: 6a513affb38dc9788b449d59ffed099b8de18fa0
   subpackages:
   - context
-  - context/ctxhttp
   - http2
   - http2/hpack
   - internal/timeseries
diff --git a/glide.yaml b/glide.yaml
index c6d1991f..07337a1d 100644
--- a/glide.yaml
+++ b/glide.yaml
@@ -35,7 +35,6 @@ import:
   version: 6a513affb38dc9788b449d59ffed099b8de18fa0
   subpackages:
   - context
-  - context/ctxhttp
   - http2
   - http2/hpack
   - internal/timeseries
@@ -68,7 +67,7 @@ import:
 
 # Used for server integration tests and OpenID Connect connector.
 - package: github.com/coreos/go-oidc
-  version: 2b5d73091ea4b7ddb15e3ac00077f153120b5b61
+  version: be73733bb8cc830d0205609b95d125215f8e9c70
 - package: github.com/pquerna/cachecontrol
   version: c97913dcbd76de40b051a9b4cd827f7eaeb7a868
 - package: golang.org/x/oauth2
diff --git a/server/api.go b/server/api.go
index 25655d68..0e7c5b2f 100644
--- a/server/api.go
+++ b/server/api.go
@@ -5,6 +5,9 @@ import (
 	"fmt"
 
 	"golang.org/x/crypto/bcrypt"
+
+	// go-grpc doesn't use the standard library's context.
+	// https://github.com/grpc/grpc-go/issues/711
 	"golang.org/x/net/context"
 
 	"github.com/Sirupsen/logrus"
diff --git a/server/rotation.go b/server/rotation.go
index fb790c62..5619b3a7 100644
--- a/server/rotation.go
+++ b/server/rotation.go
@@ -1,6 +1,7 @@
 package server
 
 import (
+	"context"
 	"crypto/rand"
 	"crypto/rsa"
 	"encoding/hex"
@@ -9,7 +10,6 @@ import (
 	"io"
 	"time"
 
-	"golang.org/x/net/context"
 	"gopkg.in/square/go-jose.v2"
 
 	"github.com/Sirupsen/logrus"
diff --git a/server/server.go b/server/server.go
index 012802f2..68fe0915 100644
--- a/server/server.go
+++ b/server/server.go
@@ -1,6 +1,7 @@
 package server
 
 import (
+	"context"
 	"errors"
 	"fmt"
 	"net/http"
@@ -10,7 +11,6 @@ import (
 	"time"
 
 	"golang.org/x/crypto/bcrypt"
-	"golang.org/x/net/context"
 
 	"github.com/Sirupsen/logrus"
 	"github.com/gorilla/handlers"
diff --git a/storage/kubernetes/client.go b/storage/kubernetes/client.go
index 1f562165..f61c37db 100644
--- a/storage/kubernetes/client.go
+++ b/storage/kubernetes/client.go
@@ -2,6 +2,7 @@ package kubernetes
 
 import (
 	"bytes"
+	"context"
 	"crypto/tls"
 	"crypto/x509"
 	"encoding/base32"
@@ -24,7 +25,6 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/ghodss/yaml"
 	"github.com/gtank/cryptopasta"
-	"golang.org/x/net/context"
 	"golang.org/x/net/http2"
 
 	"github.com/coreos/dex/storage"
diff --git a/storage/kubernetes/storage.go b/storage/kubernetes/storage.go
index 788d08b1..5b8721f3 100644
--- a/storage/kubernetes/storage.go
+++ b/storage/kubernetes/storage.go
@@ -1,13 +1,12 @@
 package kubernetes
 
 import (
+	"context"
 	"errors"
 	"fmt"
 	"strings"
 	"time"
 
-	"golang.org/x/net/context"
-
 	"github.com/Sirupsen/logrus"
 	"github.com/coreos/dex/storage"
 	"github.com/coreos/dex/storage/kubernetes/k8sapi"
@@ -85,6 +84,7 @@ func (c *Config) open(logger logrus.FieldLogger, errOnTPRs bool) (*client, error
 
 	if !cli.createThirdPartyResources() {
 		if errOnTPRs {
+			cancel()
 			return nil, fmt.Errorf("failed creating third party resources")
 		}
 
diff --git a/vendor/github.com/coreos/go-oidc/jwks.go b/vendor/github.com/coreos/go-oidc/jwks.go
index 413f392f..0f3cf0c9 100644
--- a/vendor/github.com/coreos/go-oidc/jwks.go
+++ b/vendor/github.com/coreos/go-oidc/jwks.go
@@ -1,6 +1,7 @@
 package oidc
 
 import (
+	"context"
 	"encoding/json"
 	"fmt"
 	"io/ioutil"
@@ -9,8 +10,6 @@ import (
 	"time"
 
 	"github.com/pquerna/cachecontrol"
-	"golang.org/x/net/context"
-	"golang.org/x/net/context/ctxhttp"
 	jose "gopkg.in/square/go-jose.v2"
 )
 
@@ -163,7 +162,7 @@ func (r *remoteKeySet) updateKeys(ctx context.Context) error {
 		return fmt.Errorf("oidc: can't create request: %v", err)
 	}
 
-	resp, err := ctxhttp.Do(ctx, clientFromContext(ctx), req)
+	resp, err := doRequest(ctx, req)
 	if err != nil {
 		return fmt.Errorf("oidc: get keys failed %v", err)
 	}
diff --git a/vendor/github.com/coreos/go-oidc/oidc.go b/vendor/github.com/coreos/go-oidc/oidc.go
index 62be15d3..a14dca0c 100644
--- a/vendor/github.com/coreos/go-oidc/oidc.go
+++ b/vendor/github.com/coreos/go-oidc/oidc.go
@@ -2,6 +2,7 @@
 package oidc
 
 import (
+	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -10,8 +11,6 @@ import (
 	"strings"
 	"time"
 
-	"golang.org/x/net/context"
-	"golang.org/x/net/context/ctxhttp"
 	"golang.org/x/oauth2"
 	jose "gopkg.in/square/go-jose.v2"
 )
@@ -46,11 +45,12 @@ func ClientContext(ctx context.Context, client *http.Client) context.Context {
 	return context.WithValue(ctx, oauth2.HTTPClient, client)
 }
 
-func clientFromContext(ctx context.Context) *http.Client {
-	if client, ok := ctx.Value(oauth2.HTTPClient).(*http.Client); ok {
-		return client
+func doRequest(ctx context.Context, req *http.Request) (*http.Response, error) {
+	client := http.DefaultClient
+	if c, ok := ctx.Value(oauth2.HTTPClient).(*http.Client); ok {
+		client = c
 	}
-	return http.DefaultClient
+	return client.Do(req.WithContext(ctx))
 }
 
 // Provider represents an OpenID Connect server's configuration.
@@ -85,7 +85,11 @@ type providerJSON struct {
 // or "https://login.salesforce.com".
 func NewProvider(ctx context.Context, issuer string) (*Provider, error) {
 	wellKnown := strings.TrimSuffix(issuer, "/") + "/.well-known/openid-configuration"
-	resp, err := ctxhttp.Get(ctx, clientFromContext(ctx), wellKnown)
+	req, err := http.NewRequest("GET", wellKnown, nil)
+	if err != nil {
+		return nil, err
+	}
+	resp, err := doRequest(ctx, req)
 	if err != nil {
 		return nil, err
 	}
@@ -174,7 +178,7 @@ func (p *Provider) UserInfo(ctx context.Context, tokenSource oauth2.TokenSource)
 	}
 	token.SetAuthHeader(req)
 
-	resp, err := ctxhttp.Do(ctx, clientFromContext(ctx), req)
+	resp, err := doRequest(ctx, req)
 	if err != nil {
 		return nil, err
 	}
@@ -201,19 +205,35 @@ func (p *Provider) UserInfo(ctx context.Context, tokenSource oauth2.TokenSource)
 // The ID Token only holds fields OpenID Connect requires. To access additional
 // claims returned by the server, use the Claims method.
 type IDToken struct {
-	// The URL of the server which issued this token. This will always be the same
-	// as the URL used for initial discovery.
+	// The URL of the server which issued this token. OpenID Connect
+	// requires this value always be identical to the URL used for
+	// initial discovery.
+	//
+	// Note: Because of a known issue with Google Accounts' implementation
+	// this value may differ when using Google.
+	//
+	// See: https://developers.google.com/identity/protocols/OpenIDConnect#obtainuserinfo
 	Issuer string
 
-	// The client, or set of clients, that this token is issued for.
+	// The client ID, or set of client IDs, that this token is issued for. For
+	// common uses, this is the client that initialized the auth flow.
+	//
+	// This package ensures the audience contains an expected value.
 	Audience []string
 
 	// A unique string which identifies the end user.
 	Subject string
 
+	// Expiry of the token. Ths package will not process tokens that have
+	// expired unless that validation is explicitly turned off.
+	Expiry time.Time
+	// When the token was issued by the provider.
 	IssuedAt time.Time
-	Expiry   time.Time
-	Nonce    string
+
+	// Initial nonce provided during the authentication redirect.
+	//
+	// If present, this package ensures this is a valid nonce.
+	Nonce string
 
 	// Raw payload of the id_token.
 	claims []byte
diff --git a/vendor/github.com/coreos/go-oidc/verify.go b/vendor/github.com/coreos/go-oidc/verify.go
index 67185a26..2b67aa9c 100644
--- a/vendor/github.com/coreos/go-oidc/verify.go
+++ b/vendor/github.com/coreos/go-oidc/verify.go
@@ -2,6 +2,7 @@ package oidc
 
 import (
 	"bytes"
+	"context"
 	"encoding/base64"
 	"encoding/json"
 	"errors"
@@ -9,61 +10,71 @@ import (
 	"strings"
 	"time"
 
-	"golang.org/x/net/context"
 	"golang.org/x/oauth2"
 	jose "gopkg.in/square/go-jose.v2"
 )
 
+const (
+	issuerGoogleAccounts         = "https://accounts.google.com"
+	issuerGoogleAccountsNoScheme = "accounts.google.com"
+)
+
 // IDTokenVerifier provides verification for ID Tokens.
 type IDTokenVerifier struct {
 	keySet *remoteKeySet
-	config *verificationConfig
-}
-
-// verificationConfig is the unexported configuration for an IDTokenVerifier.
-//
-// Users interact with this struct using a VerificationOption.
-type verificationConfig struct {
+	config *Config
 	issuer string
-	// If provided, this value must be in the ID Token audiences.
-	audience string
-	// If not nil, check the expiry of the id token.
-	checkExpiry func() time.Time
-	// If specified, only these sets of algorithms may be used to sign the JWT.
-	requiredAlgs []string
-	// If not nil, don't verify nonce.
-	nonceSource NonceSource
 }
 
-// VerificationOption provides additional checks on ID Tokens.
-type VerificationOption interface {
-	// Unexport this method so other packages can't implement this interface.
-	updateConfig(c *verificationConfig)
+// Config is the configuration for an IDTokenVerifier.
+type Config struct {
+	// Expected audience of the token. For a majority of the cases this is expected to be
+	// the ID of the client that initialized the login flow. It may occasionally differ if
+	// the provider supports the authorizing party (azp) claim.
+	//
+	// If not provided, users must explicitly set SkipClientIDCheck.
+	ClientID string
+	// Method to verify the ID Token nonce. If a nonce is present and this method
+	// is nil, users must explicitly set SkipNonceCheck.
+	//
+	// If the ID Token nonce is empty, for example if the client didn't provide a nonce in
+	// the initial redirect, this may be nil.
+	ClaimNonce func(nonce string) error
+	// If specified, only this set of algorithms may be used to sign the JWT.
+	//
+	// Since many providers only support RS256, SupportedSigningAlgs defaults to this value.
+	SupportedSigningAlgs []string
+
+	// If true, no ClientID check performed. Must be true if ClientID field is empty.
+	SkipClientIDCheck bool
+	// If true, token expiry is not checked.
+	SkipExpiryCheck bool
+	// If true, nonce claim is not checked. Must be true if ClaimNonce field is empty.
+	SkipNonceCheck bool
+
+	// Time function to check Token expiry. Defaults to time.Now
+	Now func() time.Time
 }
 
 // Verifier returns an IDTokenVerifier that uses the provider's key set to verify JWTs.
 //
 // The returned IDTokenVerifier is tied to the Provider's context and its behavior is
 // undefined once the Provider's context is canceled.
-func (p *Provider) Verifier(options ...VerificationOption) *IDTokenVerifier {
-	config := &verificationConfig{issuer: p.issuer}
-	for _, option := range options {
-		option.updateConfig(config)
-	}
+func (p *Provider) Verifier(config *Config) *IDTokenVerifier {
 
-	return newVerifier(p.remoteKeySet, config)
+	return newVerifier(p.remoteKeySet, config, p.issuer)
 }
 
-func newVerifier(keySet *remoteKeySet, config *verificationConfig) *IDTokenVerifier {
-	// As discussed in the godocs for VerifrySigningAlg, because almost all providers
-	// only support RS256, default to only allowing it.
-	if len(config.requiredAlgs) == 0 {
-		config.requiredAlgs = []string{RS256}
+func newVerifier(keySet *remoteKeySet, config *Config, issuer string) *IDTokenVerifier {
+	// If SupportedSigningAlgs is empty defaults to only support RS256.
+	if len(config.SupportedSigningAlgs) == 0 {
+		config.SupportedSigningAlgs = []string{RS256}
 	}
 
 	return &IDTokenVerifier{
 		keySet: keySet,
 		config: config,
+		issuer: issuer,
 	}
 }
 
@@ -89,7 +100,7 @@ func contains(sli []string, ele string) bool {
 }
 
 // Verify parses a raw ID Token, verifies it's been signed by the provider, preforms
-// any additional checks passed as VerifictionOptions, and returns the payload.
+// any additional checks depending on the Config, and returns the payload.
 //
 // See: https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
 //
@@ -134,20 +145,38 @@ func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDTok
 	}
 
 	// Check issuer.
-	if t.Issuer != v.config.issuer {
-		return nil, fmt.Errorf("oidc: id token issued by a different provider, expected %q got %q", v.config.issuer, t.Issuer)
+	if t.Issuer != v.issuer {
+		// Google sometimes returns "accounts.google.com" as the issuer claim instead of
+		// the required "https://accounts.google.com". Detect this case and allow it only
+		// for Google.
+		//
+		// We will not add hooks to let other providers go off spec like this.
+		if !(v.issuer == issuerGoogleAccounts && t.Issuer == issuerGoogleAccountsNoScheme) {
+			return nil, fmt.Errorf("oidc: id token issued by a different provider, expected %q got %q", v.issuer, t.Issuer)
+		}
 	}
 
-	// If a client ID has been provided, make sure it's part of the audience.
-	if v.config.audience != "" {
-		if !contains(t.Audience, v.config.audience) {
-			return nil, fmt.Errorf("oidc: expected audience %q got %q", v.config.audience, t.Audience)
+	// If a client ID has been provided, make sure it's part of the audience. SkipClientIDCheck must be true if ClientID is empty.
+	//
+	// This check DOES NOT ensure that the ClientID is the party to which the ID Token was issued (i.e. Authorized party).
+	if !v.config.SkipClientIDCheck {
+		if v.config.ClientID != "" {
+			if !contains(t.Audience, v.config.ClientID) {
+				return nil, fmt.Errorf("oidc: expected audience %q got %q", v.config.ClientID, t.Audience)
+			}
+		} else {
+			return nil, fmt.Errorf("oidc: Invalid configuration. ClientID must be provided or SkipClientIDCheck must be set.")
 		}
 	}
 
-	// If a checkExpiry is specified, make sure token is not expired.
-	if v.config.checkExpiry != nil {
-		if t.Expiry.Before(v.config.checkExpiry()) {
+	// If a SkipExpiryCheck is false, make sure token is not expired.
+	if !v.config.SkipExpiryCheck {
+		now := time.Now
+		if v.config.Now != nil {
+			now = v.config.Now
+		}
+
+		if t.Expiry.Before(now()) {
 			return nil, fmt.Errorf("oidc: token is expired (Token Expiry: %v)", t.Expiry)
 		}
 	}
@@ -155,14 +184,14 @@ func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDTok
 	// If a set of required algorithms has been provided, ensure that the signatures use those.
 	var keyIDs, gotAlgs []string
 	for _, sig := range jws.Signatures {
-		if len(v.config.requiredAlgs) == 0 || contains(v.config.requiredAlgs, sig.Header.Algorithm) {
+		if len(v.config.SupportedSigningAlgs) == 0 || contains(v.config.SupportedSigningAlgs, sig.Header.Algorithm) {
 			keyIDs = append(keyIDs, sig.Header.KeyID)
 		} else {
 			gotAlgs = append(gotAlgs, sig.Header.Algorithm)
 		}
 	}
 	if len(keyIDs) == 0 {
-		return nil, fmt.Errorf("oidc: no signatures use a require algorithm, expected %q got %q", v.config.requiredAlgs, gotAlgs)
+		return nil, fmt.Errorf("oidc: no signatures use a supported algorithm, expected %q got %q", v.config.SupportedSigningAlgs, gotAlgs)
 	}
 
 	// Get keys from the remote key set. This may trigger a re-sync.
@@ -192,79 +221,22 @@ func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDTok
 
 	// Check the nonce after we've verified the token. We don't want to allow unverified
 	// payloads to trigger a nonce lookup.
-	if v.config.nonceSource != nil {
-		if err := v.config.nonceSource.ClaimNonce(t.Nonce); err != nil {
-			return nil, err
+	// If SkipNonceCheck is not set ClaimNonce cannot be Nil.
+	if !v.config.SkipNonceCheck && t.Nonce != "" {
+		if v.config.ClaimNonce != nil {
+			if err := v.config.ClaimNonce(t.Nonce); err != nil {
+				return nil, err
+			}
+		} else {
+			return nil, fmt.Errorf("oidc: Invalid configuration. ClaimNonce must be provided or SkipNonceCheck must be set.")
 		}
 	}
 
 	return t, nil
 }
 
-// VerifyAudience ensures that an ID Token was issued for the specific client.
-//
-// Note that a verified token may be valid for other clients, as OpenID Connect allows a token to have
-// multiple audiences.
-func VerifyAudience(clientID string) VerificationOption {
-	return clientVerifier{clientID}
-}
-
-type clientVerifier struct {
-	clientID string
-}
-
-func (v clientVerifier) updateConfig(c *verificationConfig) {
-	c.audience = v.clientID
-}
-
-// VerifyExpiry ensures that an ID Token has not expired.
-func VerifyExpiry() VerificationOption {
-	return expiryVerifier{}
-}
-
-type expiryVerifier struct{}
-
-func (v expiryVerifier) updateConfig(c *verificationConfig) {
-	c.checkExpiry = time.Now
-}
-
-// VerifySigningAlg enforces that an ID Token is signed by a specific signing algorithm.
-//
-// Because so many providers only support RS256, if this verifiction option isn't used,
-// the IDTokenVerifier defaults to only allowing RS256.
-func VerifySigningAlg(allowedAlgs ...string) VerificationOption {
-	return algVerifier{allowedAlgs}
-}
-
-type algVerifier struct {
-	algs []string
-}
-
-func (v algVerifier) updateConfig(c *verificationConfig) {
-	c.requiredAlgs = v.algs
-}
-
 // Nonce returns an auth code option which requires the ID Token created by the
 // OpenID Connect provider to contain the specified nonce.
 func Nonce(nonce string) oauth2.AuthCodeOption {
 	return oauth2.SetAuthURLParam("nonce", nonce)
 }
-
-// NonceSource represents a source which can verify a nonce is valid and has not
-// been claimed before.
-type NonceSource interface {
-	ClaimNonce(nonce string) error
-}
-
-// VerifyNonce ensures that the ID Token contains a nonce which can be claimed by the nonce source.
-func VerifyNonce(source NonceSource) VerificationOption {
-	return nonceVerifier{source}
-}
-
-type nonceVerifier struct {
-	nonceSource NonceSource
-}
-
-func (n nonceVerifier) updateConfig(c *verificationConfig) {
-	c.nonceSource = n.nonceSource
-}
diff --git a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
deleted file mode 100644
index 606cf1f9..00000000
--- a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.7
-
-// Package ctxhttp provides helper functions for performing context-aware HTTP requests.
-package ctxhttp // import "golang.org/x/net/context/ctxhttp"
-
-import (
-	"io"
-	"net/http"
-	"net/url"
-	"strings"
-
-	"golang.org/x/net/context"
-)
-
-// Do sends an HTTP request with the provided http.Client and returns
-// an HTTP response.
-//
-// If the client is nil, http.DefaultClient is used.
-//
-// The provided ctx must be non-nil. If it is canceled or times out,
-// ctx.Err() will be returned.
-func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
-	if client == nil {
-		client = http.DefaultClient
-	}
-	resp, err := client.Do(req.WithContext(ctx))
-	// If we got an error, and the context has been canceled,
-	// the context's error is probably more useful.
-	if err != nil {
-		select {
-		case <-ctx.Done():
-			err = ctx.Err()
-		default:
-		}
-	}
-	return resp, err
-}
-
-// Get issues a GET request via the Do function.
-func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
-	req, err := http.NewRequest("GET", url, nil)
-	if err != nil {
-		return nil, err
-	}
-	return Do(ctx, client, req)
-}
-
-// Head issues a HEAD request via the Do function.
-func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
-	req, err := http.NewRequest("HEAD", url, nil)
-	if err != nil {
-		return nil, err
-	}
-	return Do(ctx, client, req)
-}
-
-// Post issues a POST request via the Do function.
-func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
-	req, err := http.NewRequest("POST", url, body)
-	if err != nil {
-		return nil, err
-	}
-	req.Header.Set("Content-Type", bodyType)
-	return Do(ctx, client, req)
-}
-
-// PostForm issues a POST request via the Do function.
-func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
-	return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
-}
diff --git a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
deleted file mode 100644
index 926870cc..00000000
--- a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !go1.7
-
-package ctxhttp // import "golang.org/x/net/context/ctxhttp"
-
-import (
-	"io"
-	"net/http"
-	"net/url"
-	"strings"
-
-	"golang.org/x/net/context"
-)
-
-func nop() {}
-
-var (
-	testHookContextDoneBeforeHeaders = nop
-	testHookDoReturned               = nop
-	testHookDidBodyClose             = nop
-)
-
-// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
-// If the client is nil, http.DefaultClient is used.
-// If the context is canceled or times out, ctx.Err() will be returned.
-func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
-	if client == nil {
-		client = http.DefaultClient
-	}
-
-	// TODO(djd): Respect any existing value of req.Cancel.
-	cancel := make(chan struct{})
-	req.Cancel = cancel
-
-	type responseAndError struct {
-		resp *http.Response
-		err  error
-	}
-	result := make(chan responseAndError, 1)
-
-	// Make local copies of test hooks closed over by goroutines below.
-	// Prevents data races in tests.
-	testHookDoReturned := testHookDoReturned
-	testHookDidBodyClose := testHookDidBodyClose
-
-	go func() {
-		resp, err := client.Do(req)
-		testHookDoReturned()
-		result <- responseAndError{resp, err}
-	}()
-
-	var resp *http.Response
-
-	select {
-	case <-ctx.Done():
-		testHookContextDoneBeforeHeaders()
-		close(cancel)
-		// Clean up after the goroutine calling client.Do:
-		go func() {
-			if r := <-result; r.resp != nil {
-				testHookDidBodyClose()
-				r.resp.Body.Close()
-			}
-		}()
-		return nil, ctx.Err()
-	case r := <-result:
-		var err error
-		resp, err = r.resp, r.err
-		if err != nil {
-			return resp, err
-		}
-	}
-
-	c := make(chan struct{})
-	go func() {
-		select {
-		case <-ctx.Done():
-			close(cancel)
-		case <-c:
-			// The response's Body is closed.
-		}
-	}()
-	resp.Body = &notifyingReader{resp.Body, c}
-
-	return resp, nil
-}
-
-// Get issues a GET request via the Do function.
-func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
-	req, err := http.NewRequest("GET", url, nil)
-	if err != nil {
-		return nil, err
-	}
-	return Do(ctx, client, req)
-}
-
-// Head issues a HEAD request via the Do function.
-func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
-	req, err := http.NewRequest("HEAD", url, nil)
-	if err != nil {
-		return nil, err
-	}
-	return Do(ctx, client, req)
-}
-
-// Post issues a POST request via the Do function.
-func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
-	req, err := http.NewRequest("POST", url, body)
-	if err != nil {
-		return nil, err
-	}
-	req.Header.Set("Content-Type", bodyType)
-	return Do(ctx, client, req)
-}
-
-// PostForm issues a POST request via the Do function.
-func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
-	return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
-}
-
-// notifyingReader is an io.ReadCloser that closes the notify channel after
-// Close is called or a Read fails on the underlying ReadCloser.
-type notifyingReader struct {
-	io.ReadCloser
-	notify chan<- struct{}
-}
-
-func (r *notifyingReader) Read(p []byte) (int, error) {
-	n, err := r.ReadCloser.Read(p)
-	if err != nil && r.notify != nil {
-		close(r.notify)
-		r.notify = nil
-	}
-	return n, err
-}
-
-func (r *notifyingReader) Close() error {
-	err := r.ReadCloser.Close()
-	if r.notify != nil {
-		close(r.notify)
-		r.notify = nil
-	}
-	return err
-}


Test patch:
diff --git a/connector/mock/connectortest.go b/connector/mock/connectortest.go
index b754705b..ef7749f7 100644
--- a/connector/mock/connectortest.go
+++ b/connector/mock/connectortest.go
@@ -2,13 +2,12 @@
 package mock
 
 import (
+	"context"
 	"errors"
 	"fmt"
 	"net/http"
 	"net/url"
 
-	"golang.org/x/net/context"
-
 	"github.com/Sirupsen/logrus"
 	"github.com/coreos/dex/connector"
 )
diff --git a/server/handlers_test.go b/server/handlers_test.go
index 233af279..4c410b8e 100644
--- a/server/handlers_test.go
+++ b/server/handlers_test.go
@@ -1,11 +1,10 @@
 package server
 
 import (
+	"context"
 	"net/http"
 	"net/http/httptest"
 	"testing"
-
-	"golang.org/x/net/context"
 )
 
 func TestHandleHealth(t *testing.T) {
diff --git a/server/server_test.go b/server/server_test.go
index 688c606e..2fd0229b 100644
--- a/server/server_test.go
+++ b/server/server_test.go
@@ -1,6 +1,7 @@
 package server
 
 import (
+	"context"
 	"crypto/rsa"
 	"crypto/x509"
 	"encoding/json"
@@ -24,7 +25,6 @@ import (
 	oidc "github.com/coreos/go-oidc"
 	"github.com/kylelemons/godebug/pretty"
 	"golang.org/x/crypto/bcrypt"
-	"golang.org/x/net/context"
 	"golang.org/x/oauth2"
 	jose "gopkg.in/square/go-jose.v2"
 
@@ -175,6 +175,8 @@ func TestOAuth2CodeFlow(t *testing.T) {
 	// Connector used by the tests.
 	var conn *mock.Callback
 
+	oidcConfig := &oidc.Config{SkipClientIDCheck: true}
+
 	tests := []struct {
 		name string
 		// If specified these set of scopes will be used during the test case.
@@ -189,7 +191,7 @@ func TestOAuth2CodeFlow(t *testing.T) {
 				if !ok {
 					return fmt.Errorf("no id token found")
 				}
-				if _, err := p.Verifier().Verify(ctx, idToken); err != nil {
+				if _, err := p.Verifier(oidcConfig).Verify(ctx, idToken); err != nil {
 					return fmt.Errorf("failed to verify id token: %v", err)
 				}
 				return nil
@@ -212,7 +214,7 @@ func TestOAuth2CodeFlow(t *testing.T) {
 				if !ok {
 					return fmt.Errorf("no id token found")
 				}
-				idToken, err := p.Verifier().Verify(ctx, rawIDToken)
+				idToken, err := p.Verifier(oidcConfig).Verify(ctx, rawIDToken)
 				if err != nil {
 					return fmt.Errorf("failed to verify id token: %v", err)
 				}
@@ -229,7 +231,7 @@ func TestOAuth2CodeFlow(t *testing.T) {
 				if !ok {
 					return fmt.Errorf("no id token found")
 				}
-				idToken, err := p.Verifier().Verify(ctx, rawIDToken)
+				idToken, err := p.Verifier(oidcConfig).Verify(ctx, rawIDToken)
 				if err != nil {
 					return fmt.Errorf("failed to verify id token: %v", err)
 				}
@@ -391,7 +393,7 @@ func TestOAuth2CodeFlow(t *testing.T) {
 				if !ok {
 					return fmt.Errorf("no id_token in refreshed token")
 				}
-				idToken, err := p.Verifier().Verify(ctx, rawIDToken)
+				idToken, err := p.Verifier(oidcConfig).Verify(ctx, rawIDToken)
 				if err != nil {
 					return fmt.Errorf("failed to verify id token: %v", err)
 				}
@@ -632,7 +634,10 @@ func TestOAuth2ImplicitFlow(t *testing.T) {
 
 	src := &nonceSource{nonce: nonce}
 
-	idTokenVerifier := p.Verifier(oidc.VerifyAudience(client.ID), oidc.VerifyNonce(src))
+	idTokenVerifier := p.Verifier(&oidc.Config{
+		ClientID:   client.ID,
+		ClaimNonce: src.ClaimNonce,
+	})
 
 	oauth2Config = &oauth2.Config{
 		ClientID:     client.ID,
@@ -749,7 +754,7 @@ func TestCrossClientScopes(t *testing.T) {
 					t.Errorf("no id token found: %v", err)
 					return
 				}
-				idToken, err := p.Verifier().Verify(ctx, rawIDToken)
+				idToken, err := p.Verifier(&oidc.Config{ClientID: testClientID}).Verify(ctx, rawIDToken)
 				if err != nil {
 					t.Errorf("failed to parse ID Token: %v", err)
 					return