diff --git a/.golangci.yml b/.golangci.yml
index cfb64a75bfd21900b81d5682ead8831177c40bf8..8d602489e8e5bfaba199d755d36ec5c40d51763b 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -19,7 +19,6 @@ linters:
     disable-all: true
     enable:
         - bodyclose
-        - deadcode
         - depguard
         - dogsled
         - exhaustive
@@ -42,17 +41,15 @@ linters:
         - rowserrcheck
         - sqlclosecheck
         - staticcheck
-        - structcheck
         - stylecheck
         - tparallel
         - unconvert
         - unparam
         - unused
-        - varcheck
         - whitespace
 
         # Disable temporarily until everything works with Go 1.18
-        # - typecheck
+        - typecheck
 
         # TODO: fix linter errors before enabling
         # - exhaustivestruct
diff --git a/Makefile b/Makefile
index 9c55ad2b11b25397da6188480fd2d724deb4cf34..0f1453bf497c29f03dac04aa35085bdb03db07c1 100644
--- a/Makefile
+++ b/Makefile
@@ -117,7 +117,7 @@ proto-internal:
 	@protoc --go_out=paths=source_relative:. server/internal/*.proto
 
 # Dependency versions
-GOLANGCI_VERSION = 1.46.0
+GOLANGCI_VERSION = 1.50.1
 GOTESTSUM_VERSION ?= 1.7.0
 PROTOC_VERSION = 3.15.6
 PROTOC_GEN_GO_VERSION = 1.26.0
diff --git a/connector/atlassiancrowd/atlassiancrowd.go b/connector/atlassiancrowd/atlassiancrowd.go
index e2ca94b0de9aa6fcef008d6b045fcd76c51bf0ff..aa142203415cde3cdf6a8eeb82715997cf365313 100644
--- a/connector/atlassiancrowd/atlassiancrowd.go
+++ b/connector/atlassiancrowd/atlassiancrowd.go
@@ -24,18 +24,17 @@ import (
 //
 // An example config:
 //
-//     type: atlassian-crowd
-//     config:
-//       baseURL: https://crowd.example.com/context
-//       clientID: applogin
-//       clientSecret: appP4$$w0rd
-//       # users can be restricted by a list of groups
-//       groups:
-//       - admin
-//       # Prompt for username field
-//       usernamePrompt: Login
-//		 preferredUsernameField: name
-//
+//	    type: atlassian-crowd
+//	    config:
+//	      baseURL: https://crowd.example.com/context
+//	      clientID: applogin
+//	      clientSecret: appP4$$w0rd
+//	      # users can be restricted by a list of groups
+//	      groups:
+//	      - admin
+//	      # Prompt for username field
+//	      usernamePrompt: Login
+//			 preferredUsernameField: name
 type Config struct {
 	BaseURL      string   `json:"baseURL"`
 	ClientID     string   `json:"clientID"`
diff --git a/connector/connector.go b/connector/connector.go
index aab994b4682a7529cee369a5ef04f4ba042777cb..e4cf58c0ae6e741fdf3807b42032284dc1c990c6 100644
--- a/connector/connector.go
+++ b/connector/connector.go
@@ -70,7 +70,8 @@ type CallbackConnector interface {
 }
 
 // SAMLConnector represents SAML connectors which implement the HTTP POST binding.
-//  RelayState is handled by the server.
+//
+//	RelayState is handled by the server.
 //
 // See: https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf
 // "3.5 HTTP POST Binding"
diff --git a/connector/google/google_test.go b/connector/google/google_test.go
index 83c4cba1a02c4c7fe6e71a63c021b88d506b5671..cf5977ab6a85b9bc0007418159bb10f16ad292ca 100644
--- a/connector/google/google_test.go
+++ b/connector/google/google_test.go
@@ -31,7 +31,7 @@ var (
 	callCounter = make(map[string]int)
 )
 
-func testSetup(t *testing.T) *httptest.Server {
+func testSetup() *httptest.Server {
 	mux := http.NewServeMux()
 
 	mux.HandleFunc("/admin/directory/v1/groups/", func(w http.ResponseWriter, r *http.Request) {
@@ -46,7 +46,7 @@ func testSetup(t *testing.T) *httptest.Server {
 	return httptest.NewServer(mux)
 }
 
-func newConnector(config *Config, serverURL string) (*googleConnector, error) {
+func newConnector(config *Config) (*googleConnector, error) {
 	log := logrus.New()
 	conn, err := config.Open("id", log)
 	if err != nil {
@@ -78,7 +78,7 @@ func tempServiceAccountKey() (string, error) {
 }
 
 func TestOpen(t *testing.T) {
-	ts := testSetup(t)
+	ts := testSetup()
 	defer ts.Close()
 
 	type testCase struct {
@@ -155,7 +155,7 @@ func TestOpen(t *testing.T) {
 			assert := assert.New(t)
 
 			os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", reference.adc)
-			conn, err := newConnector(reference.config, ts.URL)
+			conn, err := newConnector(reference.config)
 
 			if reference.expectedErr == "" {
 				assert.Nil(err)
@@ -168,7 +168,7 @@ func TestOpen(t *testing.T) {
 }
 
 func TestGetGroups(t *testing.T) {
-	ts := testSetup(t)
+	ts := testSetup()
 	defer ts.Close()
 
 	serviceAccountFilePath, err := tempServiceAccountKey()
@@ -181,7 +181,7 @@ func TestGetGroups(t *testing.T) {
 		RedirectURI:  ts.URL + "/callback",
 		Scopes:       []string{"openid", "groups"},
 		AdminEmail:   "admin@dexidp.com",
-	}, ts.URL)
+	})
 	assert.Nil(t, err)
 
 	conn.adminSrv, err = admin.NewService(context.Background(), option.WithoutAuthentication(), option.WithEndpoint(ts.URL))
diff --git a/connector/microsoft/microsoft.go b/connector/microsoft/microsoft.go
index 3952c94be631a72d05f22178dcebb9d237b7745e..719b92de66b8177a8d7b74d022b1ed7e2eeef396 100644
--- a/connector/microsoft/microsoft.go
+++ b/connector/microsoft/microsoft.go
@@ -316,22 +316,27 @@ func (c *microsoftConnector) Refresh(ctx context.Context, s connector.Scopes, id
 
 // https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/resources/user
 // id                - The unique identifier for the user. Inherited from
-//                     directoryObject. Key. Not nullable. Read-only.
+//
+//	directoryObject. Key. Not nullable. Read-only.
+//
 // displayName       - The name displayed in the address book for the user.
-//                     This is usually the combination of the user's first name,
-//                     middle initial and last name. This property is required
-//                     when a user is created and it cannot be cleared during
-//                     updates. Supports $filter and $orderby.
+//
+//	This is usually the combination of the user's first name,
+//	middle initial and last name. This property is required
+//	when a user is created and it cannot be cleared during
+//	updates. Supports $filter and $orderby.
+//
 // userPrincipalName - The user principal name (UPN) of the user.
-//                     The UPN is an Internet-style login name for the user
-//                     based on the Internet standard RFC 822. By convention,
-//                     this should map to the user's email name. The general
-//                     format is alias@domain, where domain must be present in
-//                     the tenant’s collection of verified domains. This
-//                     property is required when a user is created. The
-//                     verified domains for the tenant can be accessed from the
-//                     verifiedDomains property of organization. Supports
-//                     $filter and $orderby.
+//
+//	The UPN is an Internet-style login name for the user
+//	based on the Internet standard RFC 822. By convention,
+//	this should map to the user's email name. The general
+//	format is alias@domain, where domain must be present in
+//	the tenant’s collection of verified domains. This
+//	property is required when a user is created. The
+//	verified domains for the tenant can be accessed from the
+//	verifiedDomains property of organization. Supports
+//	$filter and $orderby.
 type user struct {
 	ID    string `json:"id"`
 	Name  string `json:"displayName"`
@@ -364,8 +369,9 @@ func (c *microsoftConnector) user(ctx context.Context, client *http.Client) (u u
 
 // https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/resources/group
 // displayName - The display name for the group. This property is required when
-//               a group is created and it cannot be cleared during updates.
-//               Supports $filter and $orderby.
+//
+//	a group is created and it cannot be cleared during updates.
+//	Supports $filter and $orderby.
 type group struct {
 	Name string `json:"displayName"`
 }
diff --git a/connector/saml/saml.go b/connector/saml/saml.go
index 908ec703c9753a39a51e924ac407acbbc63d253c..06712db6ec70eb8bc42dda66cdb3d9fe11000807 100644
--- a/connector/saml/saml.go
+++ b/connector/saml/saml.go
@@ -24,7 +24,7 @@ import (
 	"github.com/dexidp/dex/pkg/log"
 )
 
-// nolint
+//nolint
 const (
 	bindingRedirect = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
 	bindingPOST     = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
@@ -292,7 +292,6 @@ func (p *provider) POSTData(s connector.Scopes, id string) (action, value string
 // * Verify signature on XML document (or verify sig on assertion elements).
 // * Verify various parts of the Assertion element. Conditions, audience, etc.
 // * Map the Assertion's attribute elements to user info.
-//
 func (p *provider) HandlePOST(s connector.Scopes, samlResponse, inResponseTo string) (ident connector.Identity, err error) {
 	rawResp, err := base64.StdEncoding.DecodeString(samlResponse)
 	if err != nil {
diff --git a/connector/saml/saml_test.go b/connector/saml/saml_test.go
index 95d513ed19db27f1853c622adc963c2b09fe8e44..68c0cb1a93d7b0062255c752d0404cff0c572c25 100644
--- a/connector/saml/saml_test.go
+++ b/connector/saml/saml_test.go
@@ -24,19 +24,18 @@ import (
 // To add a new test, define a new, unsigned SAML 2.0 response that exercises some
 // case, then sign it using the "testdata/gen.sh" script.
 //
-//     cp testdata/good-resp.tmpl testdata/( testname ).tmpl
-//     vim ( testname ).tmpl # Modify your template for your test case.
-//     vim testdata/gen.sh   # Add a xmlsec1 command to the generation script.
-//     ./testdata/gen.sh     # Sign your template.
+//	cp testdata/good-resp.tmpl testdata/( testname ).tmpl
+//	vim ( testname ).tmpl # Modify your template for your test case.
+//	vim testdata/gen.sh   # Add a xmlsec1 command to the generation script.
+//	./testdata/gen.sh     # Sign your template.
 //
 // To install xmlsec1 on Fedora run:
 //
-//     sudo dnf install xmlsec1 xmlsec1-openssl
+//	sudo dnf install xmlsec1 xmlsec1-openssl
 //
 // On mac:
 //
-//     brew install Libxmlsec1
-//
+//	brew install Libxmlsec1
 type responseTest struct {
 	// CA file and XML file of the response.
 	caFile   string
diff --git a/server/oauth2.go b/server/oauth2.go
index 67223fa1c0d30c5251a42b7739b18b8dfdb923d0..bb0058a74a9728ec532c915d67eabdbe8ab4517f 100644
--- a/server/oauth2.go
+++ b/server/oauth2.go
@@ -93,7 +93,7 @@ func tokenErr(w http.ResponseWriter, typ, description string, statusCode int) er
 	return nil
 }
 
-// nolint
+//nolint
 const (
 	errInvalidRequest          = "invalid_request"
 	errUnauthorizedClient      = "unauthorized_client"
@@ -211,9 +211,9 @@ func signPayload(key *jose.JSONWebKey, alg jose.SignatureAlgorithm, payload []by
 // The hash algorithm for the at_hash is determined by the signing
 // algorithm used for the id_token. From the spec:
 //
-//    ...the hash algorithm used is the hash algorithm used in the alg Header
-//    Parameter of the ID Token's JOSE Header. For instance, if the alg is RS256,
-//    hash the access_token value with SHA-256
+//	...the hash algorithm used is the hash algorithm used in the alg Header
+//	Parameter of the ID Token's JOSE Header. For instance, if the alg is RS256,
+//	hash the access_token value with SHA-256
 //
 // https://openid.net/specs/openid-connect-core-1_0.html#ImplicitIDToken
 var hashForSigAlg = map[jose.SignatureAlgorithm]func() hash.Hash{
diff --git a/server/templates.go b/server/templates.go
index 33f00fda3649e10852d8089f97f9edfd8332808e..245378918fd96d2a785d9365cdff37222e601fe4 100644
--- a/server/templates.go
+++ b/server/templates.go
@@ -83,12 +83,11 @@ func getFuncMap(c webConfig) (template.FuncMap, error) {
 //
 // The directory layout is expected to be:
 //
-//    ( web directory )
-//    |- static
-//    |- themes
-//    |  |- (theme name)
-//    |- templates
-//
+//	( web directory )
+//	|- static
+//	|- themes
+//	|  |- (theme name)
+//	|- templates
 func loadWebConfig(c webConfig) (http.Handler, http.Handler, *templates, error) {
 	// fallback to the default theme if the legacy theme name is provided
 	if c.theme == "coreos" || c.theme == "tectonic" {
diff --git a/storage/ent/postgres.go b/storage/ent/postgres.go
index 1953f5992fbf6a8dc4b849b7c8e293adaa9b6dc0..ac091e702cf51d1b38eb6410172958ee7382d63e 100644
--- a/storage/ent/postgres.go
+++ b/storage/ent/postgres.go
@@ -20,7 +20,7 @@ import (
 	"github.com/dexidp/dex/storage/ent/db"
 )
 
-// nolint
+//nolint
 const (
 	// postgres SSL modes
 	pgSSLDisable    = "disable"
diff --git a/storage/kubernetes/client.go b/storage/kubernetes/client.go
index 1e4e75d8695d3e25f9f23c860e45629cb105de87..e99c069027a400058ddcd13b65c3bb2c444c7308 100644
--- a/storage/kubernetes/client.go
+++ b/storage/kubernetes/client.go
@@ -211,7 +211,7 @@ func (cli *client) getResource(apiVersion, namespace, resource, name string, v i
 	return cli.getURL(u, v)
 }
 
-func (cli *client) listN(resource string, v interface{}, n int) error {
+func (cli *client) listN(resource string, v interface{}, n int) error { //nolint:unparam // In practice, n is the gcResultLimit constant.
 	params := url.Values{}
 	params.Add("limit", fmt.Sprintf("%d", n))
 	u, err := cli.urlForWithParams(cli.apiVersion, cli.namespace, resource, "", params)
diff --git a/storage/kubernetes/lock.go b/storage/kubernetes/lock.go
index 798c1f161facfcf07a599a2739b9676343df6851..12075e81db6f1dcb4859bb421350770ccc6fc319 100644
--- a/storage/kubernetes/lock.go
+++ b/storage/kubernetes/lock.go
@@ -19,9 +19,9 @@ var (
 //
 // Refresh token contains data to refresh identity in external authentication system.
 // There is a requirement that refresh should be called only once because of several reasons:
-// * Some of OIDC providers could use the refresh token rotation feature which requires calling refresh only once.
-// * Providers can limit the rate of requests to the token endpoint, which will lead to the error
-//   in case of many concurrent requests.
+//   - Some of OIDC providers could use the refresh token rotation feature which requires calling refresh only once.
+//   - Providers can limit the rate of requests to the token endpoint, which will lead to the error
+//     in case of many concurrent requests.
 type refreshTokenLock struct {
 	cli          *client
 	waitingState bool
diff --git a/storage/kubernetes/transport.go b/storage/kubernetes/transport.go
index 5d39c27fba3151fbb8627c44c9a3d1b7f3188673..9c3cd2baac268bcbb5043000bc495dada7a922d5 100644
--- a/storage/kubernetes/transport.go
+++ b/storage/kubernetes/transport.go
@@ -62,15 +62,17 @@ func wrapRoundTripper(base http.RoundTripper, user k8sapi.AuthInfo, inCluster bo
 }
 
 // renewTokenPeriod is the interval after which dex will read the token from a well-known file.
-//   By Kubernetes documentation, this interval should be at least one minute long.
-//   Kubernetes client-go v0.15+ uses 10 seconds long interval.
-//   Dex uses the reasonable value between these two.
+//
+//	By Kubernetes documentation, this interval should be at least one minute long.
+//	Kubernetes client-go v0.15+ uses 10 seconds long interval.
+//	Dex uses the reasonable value between these two.
 const renewTokenPeriod = 30 * time.Second
 
 // inClusterTransportHelper is capable of safely updating the user token.
-//   BoundServiceAccountTokenVolume feature is enabled in Kubernetes >=1.21 by default.
-//   With this feature, the service account token in the pod becomes periodically updated.
-//   Therefore, Dex needs to re-read the token from the disk after some time to be sure that it uses the valid token.
+//
+//	BoundServiceAccountTokenVolume feature is enabled in Kubernetes >=1.21 by default.
+//	With this feature, the service account token in the pod becomes periodically updated.
+//	Therefore, Dex needs to re-read the token from the disk after some time to be sure that it uses the valid token.
 type inClusterTransportHelper struct {
 	mu   sync.RWMutex
 	info k8sapi.AuthInfo
diff --git a/storage/sql/config.go b/storage/sql/config.go
index 1aedf04cae7ff84a40d7bf11fb6234a452e023a9..8b782425631db56bc938a820411b2d03376c9be2 100644
--- a/storage/sql/config.go
+++ b/storage/sql/config.go
@@ -31,7 +31,7 @@ const (
 	mysqlErrUnknownSysVar       = 1193
 )
 
-// nolint
+//nolint
 const (
 	// postgres SSL modes
 	pgSSLDisable    = "disable"
@@ -40,7 +40,7 @@ const (
 	pgSSLVerifyFull = "verify-full"
 )
 
-// nolint
+//nolint
 const (
 	// MySQL SSL modes
 	mysqlSSLTrue       = "true"
diff --git a/storage/sql/crud.go b/storage/sql/crud.go
index 1583c17741253ba35219b72a5beab8712ac80c55..7f8666db05a0a1bfaae56ceea20836f3131a1559 100644
--- a/storage/sql/crud.go
+++ b/storage/sql/crud.go
@@ -21,19 +21,18 @@ const keysRowID = "keys"
 // encoder wraps the underlying value in a JSON marshaler which is automatically
 // called by the database/sql package.
 //
-//		s := []string{"planes", "bears"}
-//		err := db.Exec(`insert into t1 (id, things) values (1, $1)`, encoder(s))
-//		if err != nil {
-//			// handle error
-//		}
-//
-//		var r []byte
-//		err = db.QueryRow(`select things from t1 where id = 1;`).Scan(&r)
-//		if err != nil {
-//			// handle error
-//		}
-//		fmt.Printf("%s\n", r) // ["planes","bears"]
+//	s := []string{"planes", "bears"}
+//	err := db.Exec(`insert into t1 (id, things) values (1, $1)`, encoder(s))
+//	if err != nil {
+//		// handle error
+//	}
 //
+//	var r []byte
+//	err = db.QueryRow(`select things from t1 where id = 1;`).Scan(&r)
+//	if err != nil {
+//		// handle error
+//	}
+//	fmt.Printf("%s\n", r) // ["planes","bears"]
 func encoder(i interface{}) driver.Valuer {
 	return jsonEncoder{i}
 }
diff --git a/storage/storage.go b/storage/storage.go
index 198a70c8e6718ff790ec4d1ac1c8dc687b1eebaf..c77c191762344c7089109ef31d6aaa3be7dd600c 100644
--- a/storage/storage.go
+++ b/storage/storage.go
@@ -144,8 +144,8 @@ type Storage interface {
 // Client represents an OAuth2 client.
 //
 // For further reading see:
-//   * Trusted peers: https://developers.google.com/identity/protocols/CrossClientAuth
-//   * Public clients: https://developers.google.com/api-client-library/python/auth/installed-app
+//   - Trusted peers: https://developers.google.com/identity/protocols/CrossClientAuth
+//   - Public clients: https://developers.google.com/api-client-library/python/auth/installed-app
 type Client struct {
 	// Client ID and secret used to identify the client.
 	ID        string `json:"id" yaml:"id"`