diff --git a/.github/workflows/artifacts.yaml b/.github/workflows/artifacts.yaml
index fdf9bee2..0237b3ac 100644
--- a/.github/workflows/artifacts.yaml
+++ b/.github/workflows/artifacts.yaml
@@ -70,7 +70,7 @@ jobs:
         uses: docker/build-push-action@v3
         with:
           context: .
-          platforms: linux/amd64,linux/arm/v7,linux/arm64
+          platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le
           # cache-from: type=gha
           # cache-to: type=gha,mode=max
           push: ${{ github.event_name == 'push' }}
@@ -83,7 +83,7 @@ jobs:
           labels: ${{ steps.meta.outputs.labels }}
 
       - name: Run Trivy vulnerability scanner
-        uses: aquasecurity/trivy-action@0.6.0
+        uses: aquasecurity/trivy-action@0.7.1
         with:
           image-ref: "ghcr.io/dexidp/dex:${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}"
           format: "sarif"
diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml
index ab970267..f841d556 100644
--- a/.github/workflows/docker.yaml
+++ b/.github/workflows/docker.yaml
@@ -75,7 +75,7 @@ jobs:
         uses: docker/build-push-action@v3
         with:
           context: .
-          platforms: linux/amd64,linux/arm/v7,linux/arm64
+          platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le
           # cache-from: type=gha
           # cache-to: type=gha,mode=max
           push: ${{ github.event_name == 'push' }}
@@ -96,7 +96,7 @@ jobs:
             org.opencontainers.image.documentation=https://dexidp.io/docs/
 
       - name: Run Trivy vulnerability scanner
-        uses: aquasecurity/trivy-action@0.6.0
+        uses: aquasecurity/trivy-action@0.7.1
         with:
           image-ref: "ghcr.io/dexidp/dex:${{ steps.tags.outputs.version }}"
           format: "template"
diff --git a/Dockerfile b/Dockerfile
index b80b216e..3462ae52 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
 ARG BASE_IMAGE=alpine
 
-FROM golang:1.18.4-alpine3.15 AS builder
+FROM golang:1.19.1-alpine3.16 AS builder
 
 WORKDIR /usr/local/src/dex
 
@@ -22,26 +22,26 @@ COPY . .
 
 RUN make release-binary
 
-FROM alpine:3.16.1 AS stager
+FROM alpine:3.16.2 AS stager
 
 RUN mkdir -p /var/dex
 RUN mkdir -p /etc/dex
 COPY config.docker.yaml /etc/dex/
 
-FROM alpine:3.16.1 AS gomplate
+FROM alpine:3.16.2 AS gomplate
 
 ARG TARGETOS
 ARG TARGETARCH
 ARG TARGETVARIANT
 
-ENV GOMPLATE_VERSION=v3.10.0
+ENV GOMPLATE_VERSION=v3.11.2
 
 RUN wget -O /usr/local/bin/gomplate \
     "https://github.com/hairyhenderson/gomplate/releases/download/${GOMPLATE_VERSION}/gomplate_${TARGETOS:-linux}-${TARGETARCH:-amd64}${TARGETVARIANT}" \
     && chmod +x /usr/local/bin/gomplate
 
 # For Dependabot to detect base image versions
-FROM alpine:3.16.1 AS alpine
+FROM alpine:3.16.2 AS alpine
 FROM gcr.io/distroless/static:latest AS distroless
 
 FROM $BASE_IMAGE
diff --git a/api/v2/go.mod b/api/v2/go.mod
index d1eefc2e..a704df7c 100644
--- a/api/v2/go.mod
+++ b/api/v2/go.mod
@@ -3,8 +3,8 @@ module github.com/dexidp/dex/api/v2
 go 1.17
 
 require (
-	google.golang.org/grpc v1.47.0
-	google.golang.org/protobuf v1.28.0
+	google.golang.org/grpc v1.49.0
+	google.golang.org/protobuf v1.28.1
 )
 
 require (
diff --git a/api/v2/go.sum b/api/v2/go.sum
index a42fa0ce..1e5f1846 100644
--- a/api/v2/go.sum
+++ b/api/v2/go.sum
@@ -117,8 +117,8 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
 google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
 google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
 google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
-google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw=
+google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -131,8 +131,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
 google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/connector/authproxy/authproxy.go b/connector/authproxy/authproxy.go
index 487a3f60..87154121 100644
--- a/connector/authproxy/authproxy.go
+++ b/connector/authproxy/authproxy.go
@@ -7,6 +7,7 @@ import (
 	"fmt"
 	"net/http"
 	"net/url"
+	"strings"
 
 	"github.com/dexidp/dex/connector"
 	"github.com/dexidp/dex/pkg/log"
@@ -69,7 +70,11 @@ func (m *callback) HandleCallback(s connector.Scopes, r *http.Request) (connecto
 	groups := m.groups
 	headerGroup := r.Header.Get(m.groupHeader)
 	if headerGroup != "" {
-		groups = append(groups, headerGroup)
+		splitheaderGroup := strings.Split(headerGroup, ",")
+		for i, v := range splitheaderGroup {
+			splitheaderGroup[i] = strings.TrimSpace(v)
+		}
+		groups = append(splitheaderGroup, groups...)
 	}
 	return connector.Identity{
 		UserID:        remoteUser, // TODO: figure out if this is a bad ID value.
diff --git a/connector/authproxy/authproxy_test.go b/connector/authproxy/authproxy_test.go
new file mode 100644
index 00000000..5d42530e
--- /dev/null
+++ b/connector/authproxy/authproxy_test.go
@@ -0,0 +1,134 @@
+package authproxy
+
+import (
+	"io"
+	"net/http"
+	"reflect"
+	"testing"
+
+	"github.com/sirupsen/logrus"
+
+	"github.com/dexidp/dex/connector"
+)
+
+const (
+	testEmail        = "testuser@example.com"
+	testGroup1       = "group1"
+	testGroup2       = "group2"
+	testGroup3       = "group 3"
+	testGroup4       = "group 4"
+	testStaticGroup1 = "static1"
+	testStaticGroup2 = "static 2"
+)
+
+var logger = &logrus.Logger{Out: io.Discard, Formatter: &logrus.TextFormatter{}}
+
+func TestUser(t *testing.T) {
+	config := Config{
+		UserHeader: "X-Remote-User",
+	}
+	conn := callback{userHeader: config.UserHeader, logger: logger, pathSuffix: "/test"}
+
+	req, err := http.NewRequest("GET", "/", nil)
+	expectNil(t, err)
+	req.Header = map[string][]string{
+		"X-Remote-User": {testEmail},
+	}
+
+	ident, err := conn.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
+	expectNil(t, err)
+
+	expectEquals(t, ident.UserID, testEmail)
+	expectEquals(t, ident.Email, testEmail)
+	expectEquals(t, len(ident.Groups), 0)
+}
+
+func TestSingleGroup(t *testing.T) {
+	config := Config{
+		UserHeader:  "X-Remote-User",
+		GroupHeader: "X-Remote-Group",
+	}
+
+	conn := callback{userHeader: config.UserHeader, groupHeader: config.GroupHeader, logger: logger, pathSuffix: "/test"}
+
+	req, err := http.NewRequest("GET", "/", nil)
+	expectNil(t, err)
+	req.Header = map[string][]string{
+		"X-Remote-User":  {testEmail},
+		"X-Remote-Group": {testGroup1},
+	}
+
+	ident, err := conn.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
+	expectNil(t, err)
+
+	expectEquals(t, ident.UserID, testEmail)
+	expectEquals(t, len(ident.Groups), 1)
+	expectEquals(t, ident.Groups[0], testGroup1)
+}
+
+func TestMultipleGroup(t *testing.T) {
+	config := Config{
+		UserHeader:  "X-Remote-User",
+		GroupHeader: "X-Remote-Group",
+	}
+
+	conn := callback{userHeader: config.UserHeader, groupHeader: config.GroupHeader, logger: logger, pathSuffix: "/test"}
+
+	req, err := http.NewRequest("GET", "/", nil)
+	expectNil(t, err)
+	req.Header = map[string][]string{
+		"X-Remote-User":  {testEmail},
+		"X-Remote-Group": {testGroup1 + ", " + testGroup2 + ", " + testGroup3 + ", " + testGroup4},
+	}
+
+	ident, err := conn.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
+	expectNil(t, err)
+
+	expectEquals(t, ident.UserID, testEmail)
+	expectEquals(t, len(ident.Groups), 4)
+	expectEquals(t, ident.Groups[0], testGroup1)
+	expectEquals(t, ident.Groups[1], testGroup2)
+	expectEquals(t, ident.Groups[2], testGroup3)
+	expectEquals(t, ident.Groups[3], testGroup4)
+}
+
+func TestStaticGroup(t *testing.T) {
+	config := Config{
+		UserHeader:  "X-Remote-User",
+		GroupHeader: "X-Remote-Group",
+		Groups:      []string{"static1", "static 2"},
+	}
+
+	conn := callback{userHeader: config.UserHeader, groupHeader: config.GroupHeader, groups: config.Groups, logger: logger, pathSuffix: "/test"}
+
+	req, err := http.NewRequest("GET", "/", nil)
+	expectNil(t, err)
+	req.Header = map[string][]string{
+		"X-Remote-User":  {testEmail},
+		"X-Remote-Group": {testGroup1 + ", " + testGroup2 + ", " + testGroup3 + ", " + testGroup4},
+	}
+
+	ident, err := conn.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
+	expectNil(t, err)
+
+	expectEquals(t, ident.UserID, testEmail)
+	expectEquals(t, len(ident.Groups), 6)
+	expectEquals(t, ident.Groups[0], testGroup1)
+	expectEquals(t, ident.Groups[1], testGroup2)
+	expectEquals(t, ident.Groups[2], testGroup3)
+	expectEquals(t, ident.Groups[3], testGroup4)
+	expectEquals(t, ident.Groups[4], testStaticGroup1)
+	expectEquals(t, ident.Groups[5], testStaticGroup2)
+}
+
+func expectNil(t *testing.T, a interface{}) {
+	if a != nil {
+		t.Errorf("Expected %+v to equal nil", a)
+	}
+}
+
+func expectEquals(t *testing.T, a interface{}, b interface{}) {
+	if !reflect.DeepEqual(a, b) {
+		t.Errorf("Expected %+v to equal %+v", a, b)
+	}
+}
diff --git a/connector/google/google.go b/connector/google/google.go
index 1b515b8e..72cc6a18 100644
--- a/connector/google/google.go
+++ b/connector/google/google.go
@@ -71,7 +71,7 @@ func (c *Config) Open(id string, logger log.Logger) (conn connector.Connector, e
 		scopes = append(scopes, "profile", "email")
 	}
 
-	srv, err := createDirectoryService(c.ServiceAccountFilePath, c.AdminEmail)
+	srv, err := createDirectoryService(c.ServiceAccountFilePath, c.AdminEmail, logger)
 	if err != nil {
 		cancel()
 		return nil, fmt.Errorf("could not create directory service: %v", err)
@@ -279,37 +279,37 @@ func (c *googleConnector) getGroups(email string, fetchTransitiveGroupMembership
 	return uniqueGroups(userGroups), nil
 }
 
-// createDirectoryService loads a google service account credentials file,
-// sets up super user impersonation and creates an admin client for calling
-// the google admin api
-func createDirectoryService(serviceAccountFilePath string, email string) (*admin.Service, error) {
-	if serviceAccountFilePath == "" && email == "" {
-		return nil, nil
-	}
-	if serviceAccountFilePath == "" || email == "" {
-		return nil, fmt.Errorf("directory service requires both serviceAccountFilePath and adminEmail")
-	}
-	jsonCredentials, err := os.ReadFile(serviceAccountFilePath)
-	if err != nil {
-		return nil, fmt.Errorf("error reading credentials from file: %v", err)
+// createDirectoryService sets up super user impersonation and creates an admin client for calling
+// the google admin api. If no serviceAccountFilePath is defined, the application default credential
+// is used.
+func createDirectoryService(serviceAccountFilePath, email string, logger log.Logger) (*admin.Service, error) {
+	if email == "" {
+		return nil, fmt.Errorf("directory service requires adminEmail")
 	}
 
-	config, err := google.JWTConfigFromJSON(jsonCredentials, admin.AdminDirectoryGroupReadonlyScope)
-	if err != nil {
-		return nil, fmt.Errorf("unable to parse client secret file to config: %v", err)
-	}
-
-	// Impersonate an admin. This is mandatory for the admin APIs.
-	config.Subject = email
+	var jsonCredentials []byte
+	var err error
 
 	ctx := context.Background()
-	client := config.Client(ctx)
-
-	srv, err := admin.NewService(ctx, option.WithHTTPClient(client))
-	if err != nil {
-		return nil, fmt.Errorf("unable to create directory service %v", err)
+	if serviceAccountFilePath == "" {
+		logger.Warn("the application default credential is used since the service account file path is not used")
+		credential, err := google.FindDefaultCredentials(ctx)
+		if err != nil {
+			return nil, fmt.Errorf("failed to fetch application default credentials: %w", err)
+		}
+		jsonCredentials = credential.JSON
+	} else {
+		jsonCredentials, err = os.ReadFile(serviceAccountFilePath)
+		if err != nil {
+			return nil, fmt.Errorf("error reading credentials from file: %v", err)
+		}
 	}
-	return srv, nil
+	config, err := google.JWTConfigFromJSON(jsonCredentials, admin.AdminDirectoryGroupReadonlyScope)
+	if err != nil {
+		return nil, fmt.Errorf("unable to parse credentials to config: %v", err)
+	}
+	config.Subject = email
+	return admin.NewService(ctx, option.WithHTTPClient(config.Client(ctx)))
 }
 
 // uniqueGroups returns the unique groups of a slice
diff --git a/connector/google/google_test.go b/connector/google/google_test.go
new file mode 100644
index 00000000..5cecbec9
--- /dev/null
+++ b/connector/google/google_test.go
@@ -0,0 +1,145 @@
+package google
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"os"
+	"testing"
+
+	"github.com/sirupsen/logrus"
+	"github.com/stretchr/testify/assert"
+)
+
+func testSetup(t *testing.T) *httptest.Server {
+	mux := http.NewServeMux()
+	// TODO: mock calls
+	// mux.HandleFunc("/admin/directory/v1/groups", func(w http.ResponseWriter, r *http.Request) {
+	// 	w.Header().Add("Content-Type", "application/json")
+	// 	json.NewEncoder(w).Encode(&admin.Groups{
+	// 		Groups: []*admin.Group{},
+	// 	})
+	// })
+	return httptest.NewServer(mux)
+}
+
+func newConnector(config *Config, serverURL string) (*googleConnector, error) {
+	log := logrus.New()
+	conn, err := config.Open("id", log)
+	if err != nil {
+		return nil, err
+	}
+
+	googleConn, ok := conn.(*googleConnector)
+	if !ok {
+		return nil, fmt.Errorf("failed to convert to googleConnector")
+	}
+	return googleConn, nil
+}
+
+func tempServiceAccountKey() (string, error) {
+	fd, err := os.CreateTemp("", "google_service_account_key")
+	if err != nil {
+		return "", err
+	}
+	defer fd.Close()
+	err = json.NewEncoder(fd).Encode(map[string]string{
+		"type":                 "service_account",
+		"project_id":           "sample-project",
+		"private_key_id":       "sample-key-id",
+		"private_key":          "-----BEGIN PRIVATE KEY-----\nsample-key\n-----END PRIVATE KEY-----\n",
+		"client_id":            "sample-client-id",
+		"client_x509_cert_url": "localhost",
+	})
+	return fd.Name(), err
+}
+
+func TestOpen(t *testing.T) {
+	ts := testSetup(t)
+	defer ts.Close()
+
+	type testCase struct {
+		config      *Config
+		expectedErr string
+
+		// string to set in GOOGLE_APPLICATION_CREDENTIALS. As local development environments can
+		// already contain ADC, test cases will be built uppon this setting this env variable
+		adc string
+	}
+
+	serviceAccountFilePath, err := tempServiceAccountKey()
+	assert.Nil(t, err)
+
+	for name, reference := range map[string]testCase{
+		"missing_admin_email": {
+			config: &Config{
+				ClientID:     "testClient",
+				ClientSecret: "testSecret",
+				RedirectURI:  ts.URL + "/callback",
+				Scopes:       []string{"openid", "groups"},
+			},
+			expectedErr: "requires adminEmail",
+		},
+		"service_account_key_not_found": {
+			config: &Config{
+				ClientID:               "testClient",
+				ClientSecret:           "testSecret",
+				RedirectURI:            ts.URL + "/callback",
+				Scopes:                 []string{"openid", "groups"},
+				AdminEmail:             "foo@bar.com",
+				ServiceAccountFilePath: "not_found.json",
+			},
+			expectedErr: "error reading credentials",
+		},
+		"service_account_key_valid": {
+			config: &Config{
+				ClientID:               "testClient",
+				ClientSecret:           "testSecret",
+				RedirectURI:            ts.URL + "/callback",
+				Scopes:                 []string{"openid", "groups"},
+				AdminEmail:             "foo@bar.com",
+				ServiceAccountFilePath: serviceAccountFilePath,
+			},
+			expectedErr: "",
+		},
+		"adc": {
+			config: &Config{
+				ClientID:     "testClient",
+				ClientSecret: "testSecret",
+				RedirectURI:  ts.URL + "/callback",
+				Scopes:       []string{"openid", "groups"},
+				AdminEmail:   "foo@bar.com",
+			},
+			adc:         serviceAccountFilePath,
+			expectedErr: "",
+		},
+		"adc_priority": {
+			config: &Config{
+				ClientID:               "testClient",
+				ClientSecret:           "testSecret",
+				RedirectURI:            ts.URL + "/callback",
+				Scopes:                 []string{"openid", "groups"},
+				AdminEmail:             "foo@bar.com",
+				ServiceAccountFilePath: serviceAccountFilePath,
+			},
+			adc:         "/dev/null",
+			expectedErr: "",
+		},
+	} {
+		reference := reference
+		t.Run(name, func(t *testing.T) {
+			assert := assert.New(t)
+
+			os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", reference.adc)
+			conn, err := newConnector(reference.config, ts.URL)
+
+			if reference.expectedErr == "" {
+				assert.Nil(err)
+				assert.NotNil(conn)
+			} else {
+				assert.ErrorContains(err, reference.expectedErr)
+			}
+		})
+	}
+}
diff --git a/connector/keystone/keystone.go b/connector/keystone/keystone.go
index db97b5a7..03f47331 100644
--- a/connector/keystone/keystone.go
+++ b/connector/keystone/keystone.go
@@ -18,6 +18,7 @@ type conn struct {
 	Host          string
 	AdminUsername string
 	AdminPassword string
+	client        *http.Client
 	Logger        log.Logger
 }
 
@@ -35,6 +36,7 @@ type domainKeystone struct {
 // Config holds the configuration parameters for Keystone connector.
 // Keystone should expose API v3
 // An example config:
+//
 //	connectors:
 //		type: keystone
 //		id: keystone
@@ -111,11 +113,12 @@ var (
 // Open returns an authentication strategy using Keystone.
 func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
 	return &conn{
-		c.Domain,
-		c.Host,
-		c.AdminUsername,
-		c.AdminPassword,
-		logger,
+		Domain:        c.Domain,
+		Host:          c.Host,
+		AdminUsername: c.AdminUsername,
+		AdminPassword: c.AdminPassword,
+		Logger:        logger,
+		client:        http.DefaultClient,
 	}, nil
 }
 
@@ -192,7 +195,6 @@ func (p *conn) Refresh(
 }
 
 func (p *conn) getTokenResponse(ctx context.Context, username, pass string) (response *http.Response, err error) {
-	client := &http.Client{}
 	jsonData := loginRequestData{
 		auth: auth{
 			Identity: identity{
@@ -221,7 +223,7 @@ func (p *conn) getTokenResponse(ctx context.Context, username, pass string) (res
 	req.Header.Set("Content-Type", "application/json")
 	req = req.WithContext(ctx)
 
-	return client.Do(req)
+	return p.client.Do(req)
 }
 
 func (p *conn) getAdminToken(ctx context.Context) (string, error) {
@@ -243,7 +245,6 @@ func (p *conn) checkIfUserExists(ctx context.Context, userID string, token strin
 func (p *conn) getUser(ctx context.Context, userID string, token string) (*userResponse, error) {
 	// https://developer.openstack.org/api-ref/identity/v3/#show-user-details
 	userURL := p.Host + "/v3/users/" + userID
-	client := &http.Client{}
 	req, err := http.NewRequest("GET", userURL, nil)
 	if err != nil {
 		return nil, err
@@ -251,7 +252,7 @@ func (p *conn) getUser(ctx context.Context, userID string, token string) (*userR
 
 	req.Header.Set("X-Auth-Token", token)
 	req = req.WithContext(ctx)
-	resp, err := client.Do(req)
+	resp, err := p.client.Do(req)
 	if err != nil {
 		return nil, err
 	}
@@ -276,7 +277,6 @@ func (p *conn) getUser(ctx context.Context, userID string, token string) (*userR
 }
 
 func (p *conn) getUserGroups(ctx context.Context, userID string, token string) ([]string, error) {
-	client := &http.Client{}
 	// https://developer.openstack.org/api-ref/identity/v3/#list-groups-to-which-a-user-belongs
 	groupsURL := p.Host + "/v3/users/" + userID + "/groups"
 	req, err := http.NewRequest("GET", groupsURL, nil)
@@ -285,7 +285,7 @@ func (p *conn) getUserGroups(ctx context.Context, userID string, token string) (
 	}
 	req.Header.Set("X-Auth-Token", token)
 	req = req.WithContext(ctx)
-	resp, err := client.Do(req)
+	resp, err := p.client.Do(req)
 	if err != nil {
 		p.Logger.Errorf("keystone: error while fetching user %q groups\n", userID)
 		return nil, err
diff --git a/connector/keystone/keystone_test.go b/connector/keystone/keystone_test.go
index fc6c01e2..8f1ea1bb 100644
--- a/connector/keystone/keystone_test.go
+++ b/connector/keystone/keystone_test.go
@@ -42,8 +42,6 @@ type groupResponse struct {
 
 func getAdminToken(t *testing.T, adminName, adminPass string) (token, id string) {
 	t.Helper()
-	client := &http.Client{}
-
 	jsonData := loginRequestData{
 		auth: auth{
 			Identity: identity{
@@ -70,7 +68,7 @@ func getAdminToken(t *testing.T, adminName, adminPass string) (token, id string)
 	}
 
 	req.Header.Set("Content-Type", "application/json")
-	resp, err := client.Do(req)
+	resp, err := http.DefaultClient.Do(req)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -93,7 +91,6 @@ func getAdminToken(t *testing.T, adminName, adminPass string) (token, id string)
 
 func createUser(t *testing.T, token, userName, userEmail, userPass string) string {
 	t.Helper()
-	client := &http.Client{}
 
 	createUserData := map[string]interface{}{
 		"user": map[string]interface{}{
@@ -116,7 +113,7 @@ func createUser(t *testing.T, token, userName, userEmail, userPass string) strin
 	}
 	req.Header.Set("X-Auth-Token", token)
 	req.Header.Add("Content-Type", "application/json")
-	resp, err := client.Do(req)
+	resp, err := http.DefaultClient.Do(req)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -139,7 +136,6 @@ func createUser(t *testing.T, token, userName, userEmail, userPass string) strin
 // delete group or user
 func deleteResource(t *testing.T, token, id, uri string) {
 	t.Helper()
-	client := &http.Client{}
 
 	deleteURI := uri + id
 	req, err := http.NewRequest("DELETE", deleteURI, nil)
@@ -148,7 +144,7 @@ func deleteResource(t *testing.T, token, id, uri string) {
 	}
 	req.Header.Set("X-Auth-Token", token)
 
-	resp, err := client.Do(req)
+	resp, err := http.DefaultClient.Do(req)
 	if err != nil {
 		t.Fatalf("error: %v", err)
 	}
@@ -157,7 +153,6 @@ func deleteResource(t *testing.T, token, id, uri string) {
 
 func createGroup(t *testing.T, token, description, name string) string {
 	t.Helper()
-	client := &http.Client{}
 
 	createGroupData := map[string]interface{}{
 		"group": map[string]interface{}{
@@ -177,7 +172,7 @@ func createGroup(t *testing.T, token, description, name string) string {
 	}
 	req.Header.Set("X-Auth-Token", token)
 	req.Header.Add("Content-Type", "application/json")
-	resp, err := client.Do(req)
+	resp, err := http.DefaultClient.Do(req)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -200,14 +195,13 @@ func createGroup(t *testing.T, token, description, name string) string {
 func addUserToGroup(t *testing.T, token, groupID, userID string) error {
 	t.Helper()
 	uri := groupsURL + groupID + "/users/" + userID
-	client := &http.Client{}
 	req, err := http.NewRequest("PUT", uri, nil)
 	if err != nil {
 		return err
 	}
 	req.Header.Set("X-Auth-Token", token)
 
-	resp, err := client.Do(req)
+	resp, err := http.DefaultClient.Do(req)
 	if err != nil {
 		t.Fatalf("error: %v", err)
 	}
@@ -219,7 +213,8 @@ func addUserToGroup(t *testing.T, token, groupID, userID string) error {
 func TestIncorrectCredentialsLogin(t *testing.T) {
 	setupVariables(t)
 	c := conn{
-		Host: keystoneURL, Domain: testDomain,
+		client: http.DefaultClient,
+		Host:   keystoneURL, Domain: testDomain,
 		AdminUsername: adminUser, AdminPassword: adminPass,
 	}
 	s := connector.Scopes{OfflineAccess: true, Groups: true}
@@ -296,7 +291,8 @@ func TestValidUserLogin(t *testing.T) {
 			defer deleteResource(t, token, userID, usersURL)
 
 			c := conn{
-				Host: keystoneURL, Domain: tt.input.domain,
+				client: http.DefaultClient,
+				Host:   keystoneURL, Domain: tt.input.domain,
 				AdminUsername: adminUser, AdminPassword: adminPass,
 			}
 			s := connector.Scopes{OfflineAccess: true, Groups: true}
@@ -333,7 +329,8 @@ func TestUseRefreshToken(t *testing.T) {
 	defer deleteResource(t, token, groupID, groupsURL)
 
 	c := conn{
-		Host: keystoneURL, Domain: testDomain,
+		client: http.DefaultClient,
+		Host:   keystoneURL, Domain: testDomain,
 		AdminUsername: adminUser, AdminPassword: adminPass,
 	}
 	s := connector.Scopes{OfflineAccess: true, Groups: true}
@@ -358,7 +355,8 @@ func TestUseRefreshTokenUserDeleted(t *testing.T) {
 	userID := createUser(t, token, testUser, testEmail, testPass)
 
 	c := conn{
-		Host: keystoneURL, Domain: testDomain,
+		client: http.DefaultClient,
+		Host:   keystoneURL, Domain: testDomain,
 		AdminUsername: adminUser, AdminPassword: adminPass,
 	}
 	s := connector.Scopes{OfflineAccess: true, Groups: true}
@@ -388,7 +386,8 @@ func TestUseRefreshTokenGroupsChanged(t *testing.T) {
 	defer deleteResource(t, token, userID, usersURL)
 
 	c := conn{
-		Host: keystoneURL, Domain: testDomain,
+		client: http.DefaultClient,
+		Host:   keystoneURL, Domain: testDomain,
 		AdminUsername: adminUser, AdminPassword: adminPass,
 	}
 	s := connector.Scopes{OfflineAccess: true, Groups: true}
@@ -424,7 +423,8 @@ func TestNoGroupsInScope(t *testing.T) {
 	defer deleteResource(t, token, userID, usersURL)
 
 	c := conn{
-		Host: keystoneURL, Domain: testDomain,
+		client: http.DefaultClient,
+		Host:   keystoneURL, Domain: testDomain,
 		AdminUsername: adminUser, AdminPassword: adminPass,
 	}
 	s := connector.Scopes{OfflineAccess: true, Groups: false}
diff --git a/connector/microsoft/microsoft.go b/connector/microsoft/microsoft.go
index 2a8bbcfb..3952c94b 100644
--- a/connector/microsoft/microsoft.go
+++ b/connector/microsoft/microsoft.go
@@ -58,6 +58,8 @@ type Config struct {
 	// For valid values, see https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-authorization-code.
 	PromptType string `json:"promptType"`
 	DomainHint string `json:"domainHint"`
+
+	Scopes []string `json:"scopes"` // defaults to scopeUser (user.read)
 }
 
 // Open returns a strategy for logging in through Microsoft.
@@ -77,6 +79,7 @@ func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error)
 		emailToLowercase:     c.EmailToLowercase,
 		promptType:           c.PromptType,
 		domainHint:           c.DomainHint,
+		scopes:               c.Scopes,
 	}
 	// By default allow logins from both personal and business/school
 	// accounts.
@@ -122,6 +125,7 @@ type microsoftConnector struct {
 	emailToLowercase     bool
 	promptType           string
 	domainHint           string
+	scopes               []string
 }
 
 func (c *microsoftConnector) isOrgTenant() bool {
@@ -133,7 +137,12 @@ func (c *microsoftConnector) groupsRequired(groupScope bool) bool {
 }
 
 func (c *microsoftConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
-	microsoftScopes := []string{scopeUser}
+	var microsoftScopes []string
+	if len(c.scopes) > 0 {
+		microsoftScopes = c.scopes
+	} else {
+		microsoftScopes = append(microsoftScopes, scopeUser)
+	}
 	if c.groupsRequired(scopes.Groups) {
 		microsoftScopes = append(microsoftScopes, scopeGroups)
 	}
diff --git a/connector/oidc/oidc.go b/connector/oidc/oidc.go
index b4e67799..e345dca0 100644
--- a/connector/oidc/oidc.go
+++ b/connector/oidc/oidc.go
@@ -351,6 +351,11 @@ func (c *oidcConnector) createIdentity(ctx context.Context, identity connector.I
 			vs, found = claims[groupsKey].([]interface{})
 		}
 
+		// Fallback when claims[groupsKey] is a string instead of an array of strings.
+		if g, b := claims[groupsKey].(string); b {
+			groups = []string{g}
+		}
+
 		if found {
 			for _, v := range vs {
 				if s, ok := v.(string); ok {
diff --git a/connector/oidc/oidc_test.go b/connector/oidc/oidc_test.go
index d8b30b39..d94af79d 100644
--- a/connector/oidc/oidc_test.go
+++ b/connector/oidc/oidc_test.go
@@ -271,6 +271,22 @@ func TestHandleCallback(t *testing.T) {
 				"cognito:groups": []string{"group3", "group4"},
 			},
 		},
+		{
+			name:               "singularGroupResponseAsString",
+			userIDKey:          "", // not configured
+			userNameKey:        "", // not configured
+			expectUserID:       "subvalue",
+			expectUserName:     "namevalue",
+			expectGroups:       []string{"group1"},
+			expectedEmailField: "emailvalue",
+			token: map[string]interface{}{
+				"sub":            "subvalue",
+				"name":           "namevalue",
+				"groups":         "group1",
+				"email":          "emailvalue",
+				"email_verified": true,
+			},
+		},
 	}
 
 	for _, tc := range tests {
diff --git a/flake.lock b/flake.lock
index f1a44670..b67b61d9 100644
--- a/flake.lock
+++ b/flake.lock
@@ -2,11 +2,11 @@
   "nodes": {
     "flake-utils": {
       "locked": {
-        "lastModified": 1648297722,
-        "narHash": "sha256-W+qlPsiZd8F3XkzXOzAoR+mpFqzm3ekQkJNa+PIh1BQ=",
+        "lastModified": 1659877975,
+        "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
         "owner": "numtide",
         "repo": "flake-utils",
-        "rev": "0f8662f1319ad6abf89b3380dd2722369fc51ade",
+        "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
         "type": "github"
       },
       "original": {
@@ -17,11 +17,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1649225869,
-        "narHash": "sha256-u1zLtPmQzhT9mNXyM8Ey9pk7orDrIKdwooeGDEXm5xM=",
+        "lastModified": 1662019588,
+        "narHash": "sha256-oPEjHKGGVbBXqwwL+UjsveJzghWiWV0n9ogo1X6l4cw=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "b6966d911da89e5a7301aaef8b4f0a44c77e103c",
+        "rev": "2da64a81275b68fdad38af669afeda43d401e94b",
         "type": "github"
       },
       "original": {
diff --git a/flake.nix b/flake.nix
index 57aa2b05..155ebf99 100644
--- a/flake.nix
+++ b/flake.nix
@@ -7,19 +7,21 @@
   };
 
   outputs = { self, nixpkgs, flake-utils, ... }:
-    flake-utils.lib.eachDefaultSystem (system:
-      let
-        pkgs = nixpkgs.legacyPackages.${system};
-        buildDeps = with pkgs; [ git go_1_18 gnumake ];
-        devDeps = with pkgs;
-          buildDeps ++ [
-            golangci-lint
-            gotestsum
-            protobuf
-            protoc-gen-go
-            protoc-gen-go-grpc
-            kind
-          ];
-      in
-      { devShell = pkgs.mkShell { buildInputs = devDeps; }; });
+    flake-utils.lib.eachDefaultSystem (
+      system:
+        let
+          pkgs = nixpkgs.legacyPackages.${system};
+          buildDeps = with pkgs; [ git go_1_19 gnumake ];
+          devDeps = with pkgs;
+            buildDeps ++ [
+              golangci-lint
+              gotestsum
+              protobuf
+              protoc-gen-go
+              protoc-gen-go-grpc
+              kind
+            ];
+        in
+          { devShell = pkgs.mkShell { buildInputs = devDeps; }; }
+    );
 }
diff --git a/go.mod b/go.mod
index 5bd7c568..59f3a953 100644
--- a/go.mod
+++ b/go.mod
@@ -1,48 +1,48 @@
 module github.com/dexidp/dex
 
-go 1.18
+go 1.19
 
 require (
-	entgo.io/ent v0.10.1
+	entgo.io/ent v0.11.2
 	github.com/AppsFlyer/go-sundheit v0.5.0
 	github.com/Masterminds/semver v1.5.0
 	github.com/Masterminds/sprig/v3 v3.2.2
 	github.com/beevik/etree v1.1.0
-	github.com/coreos/go-oidc/v3 v3.2.0
+	github.com/coreos/go-oidc/v3 v3.4.0
 	github.com/dexidp/dex/api/v2 v2.1.0
 	github.com/felixge/httpsnoop v1.0.3
 	github.com/ghodss/yaml v1.0.0
-	github.com/go-ldap/ldap/v3 v3.4.2
+	github.com/go-ldap/ldap/v3 v3.4.4
 	github.com/go-sql-driver/mysql v1.6.0
 	github.com/gorilla/handlers v1.5.1
 	github.com/gorilla/mux v1.8.0
 	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
 	github.com/kylelemons/godebug v1.1.0
-	github.com/lib/pq v1.10.4
+	github.com/lib/pq v1.10.7
 	github.com/mattermost/xml-roundtrip-validator v0.1.0
-	github.com/mattn/go-sqlite3 v1.14.11
+	github.com/mattn/go-sqlite3 v1.14.15
 	github.com/oklog/run v1.1.0
 	github.com/pkg/errors v0.9.1
-	github.com/prometheus/client_golang v1.12.2
+	github.com/prometheus/client_golang v1.13.0
 	github.com/russellhaering/goxmldsig v1.2.0
 	github.com/sirupsen/logrus v1.9.0
 	github.com/spf13/cobra v1.5.0
 	github.com/stretchr/testify v1.8.0
 	go.etcd.io/etcd/client/pkg/v3 v3.5.4
 	go.etcd.io/etcd/client/v3 v3.5.4
-	golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab
-	golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
-	golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2
-	google.golang.org/api v0.86.0
-	google.golang.org/grpc v1.47.0
-	google.golang.org/protobuf v1.28.0
+	golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
+	golang.org/x/net v0.0.0-20220909164309-bea034e7d591
+	golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094
+	google.golang.org/api v0.97.0
+	google.golang.org/grpc v1.49.0
+	google.golang.org/protobuf v1.28.1
 	gopkg.in/square/go-jose.v2 v2.6.0
 )
 
 require (
-	ariga.io/atlas v0.3.7-0.20220303204946-787354f533c3 // indirect
+	ariga.io/atlas v0.5.1-0.20220717122844-8593d7eb1a8e // indirect
 	cloud.google.com/go/compute v1.7.0 // indirect
-	github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
+	github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
 	github.com/Masterminds/goutils v1.1.1 // indirect
 	github.com/Masterminds/semver/v3 v3.1.1 // indirect
 	github.com/agext/levenshtein v1.2.1 // indirect
@@ -52,7 +52,7 @@ require (
 	github.com/coreos/go-semver v0.3.0 // indirect
 	github.com/coreos/go-systemd/v22 v22.3.2 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
-	github.com/go-asn1-ber/asn1-ber v1.5.1 // indirect
+	github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
 	github.com/go-openapi/inflect v0.19.0 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
@@ -72,8 +72,8 @@ require (
 	github.com/mitchellh/reflectwalk v1.0.0 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/prometheus/client_model v0.2.0 // indirect
-	github.com/prometheus/common v0.32.1 // indirect
-	github.com/prometheus/procfs v0.7.3 // indirect
+	github.com/prometheus/common v0.37.0 // indirect
+	github.com/prometheus/procfs v0.8.0 // indirect
 	github.com/shopspring/decimal v1.2.0 // indirect
 	github.com/spf13/cast v1.4.1 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
@@ -83,8 +83,8 @@ require (
 	go.uber.org/atomic v1.7.0 // indirect
 	go.uber.org/multierr v1.6.0 // indirect
 	go.uber.org/zap v1.17.0 // indirect
-	golang.org/x/mod v0.5.1 // indirect
-	golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
+	golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
+	golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
 	golang.org/x/text v0.3.7 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
 	google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f // indirect
diff --git a/go.sum b/go.sum
index 2aece845..b08b99d3 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,5 @@
-ariga.io/atlas v0.3.7-0.20220303204946-787354f533c3 h1:fjG4oFCQEfGrRi0QoxWcH2OO28CE6VYa6DkIr3yDySU=
-ariga.io/atlas v0.3.7-0.20220303204946-787354f533c3/go.mod h1:yWGf4VPiD4SW83+kAqzD624txN9VKoJC+bpVXr2pKJA=
+ariga.io/atlas v0.5.1-0.20220717122844-8593d7eb1a8e h1:/r1xGMwmLg4LZ2V3/wWui9TtM3+STh1fp5ExSVRNFZo=
+ariga.io/atlas v0.5.1-0.20220717122844-8593d7eb1a8e/go.mod h1:ofVetkJqlaWle3mvYmaS2uyFGFcc7dSq436tmxa/Mzk=
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@@ -57,12 +57,12 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
 cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
 cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-entgo.io/ent v0.10.1 h1:dM5h4Zk6yHGIgw4dCqVzGw3nWgpGYJiV4/kyHEF6PFo=
-entgo.io/ent v0.10.1/go.mod h1:YPgxeLnoQ/YdpVORRtqjBF+wCy9NX9IR7veTv3Bffus=
+entgo.io/ent v0.11.2 h1:UM2/BUhF2FfsxPHRxLjQbhqJNaDdVlOwNIAMLs2jyto=
+entgo.io/ent v0.11.2/go.mod h1:YGHEQnmmIUgtD5b1ICD5vg74dS3npkNnmC5K+0J+IHU=
 github.com/AppsFlyer/go-sundheit v0.5.0 h1:/VxpyigCfJrq1r97mn9HPiAB2qrhcTFHwNIIDr15CZM=
 github.com/AppsFlyer/go-sundheit v0.5.0/go.mod h1:2ZM0BnfqT/mljBQO224VbL5XH06TgWuQ6Cn+cTtCpTY=
-github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28=
-github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
+github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU=
+github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
@@ -111,8 +111,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
 github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/coreos/go-oidc/v3 v3.2.0 h1:2eR2MGR7thBXSQ2YbODlF0fcmgtliLCfr9iX6RW11fc=
-github.com/coreos/go-oidc/v3 v3.2.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo=
+github.com/coreos/go-oidc/v3 v3.4.0 h1:xz7elHb/LDwm/ERpwHd+5nb7wFHL32rsr6bBOgaeu6g=
+github.com/coreos/go-oidc/v3 v3.4.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw=
 github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
@@ -140,19 +140,21 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8
 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
 github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8=
-github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
+github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
+github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
-github.com/go-ldap/ldap/v3 v3.4.2 h1:zFZKcXKLqZpFMrMQGHeHWKXbDTdNCmhGY9AK41zPh+8=
-github.com/go-ldap/ldap/v3 v3.4.2/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
+github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
+github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs=
+github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
 github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
 github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
 github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
@@ -298,12 +300,12 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
 github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
-github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
-github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
+github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
 github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
-github.com/mattn/go-sqlite3 v1.14.11 h1:gt+cp9c0XGqe9S/wAHTL3n/7MqY+siPWgWJgqdsFrzQ=
-github.com/mattn/go-sqlite3 v1.14.11/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
+github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
+github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
 github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
@@ -333,8 +335,9 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
 github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
 github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
-github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=
-github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
+github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
+github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
+github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -343,14 +346,16 @@ github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T
 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
-github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
 github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
+github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
+github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
-github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
+github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
@@ -389,6 +394,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
 github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
@@ -431,10 +437,9 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab h1:lnZ4LoV0UMdibeCUfIB2a4uFwRu491WX/VB2reB8xNc=
-golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -470,8 +475,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
-golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -495,7 +500,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
@@ -512,14 +516,17 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
 golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI=
+golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -540,8 +547,8 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j
 golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
 golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
 golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
-golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 h1:+jnHzr9VPj32ykQVai5DNahi9+NSp7yYuCsl5eAQtL0=
-golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
+golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 h1:2o1E+E8TpNLklK9nHiPiK1uzIYrIHt+cQx3ynCwq9V8=
+golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -623,9 +630,9 @@ golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
+golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -741,8 +748,8 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
 google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
 google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
 google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
-google.golang.org/api v0.86.0 h1:ZAnyOHQFIuWso1BodVfSaRyffD74T9ERGFa3k1fNk/U=
-google.golang.org/api v0.86.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
+google.golang.org/api v0.97.0 h1:x/vEL1XDF/2V4xzdNgFPaKHluRESo2aTsL7QzHnBtGQ=
+google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -861,8 +868,9 @@ google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5
 google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
 google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
 google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
 google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw=
+google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -877,8 +885,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
 google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -886,7 +895,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
 gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
 gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/server/deviceflowhandlers.go b/server/deviceflowhandlers.go
index 0efe3b2b..95fed3b3 100644
--- a/server/deviceflowhandlers.go
+++ b/server/deviceflowhandlers.go
@@ -73,6 +73,17 @@ func (s *Server) handleDeviceCode(w http.ResponseWriter, r *http.Request) {
 		clientID := r.Form.Get("client_id")
 		clientSecret := r.Form.Get("client_secret")
 		scopes := strings.Fields(r.Form.Get("scope"))
+		codeChallenge := r.Form.Get("code_challenge")
+		codeChallengeMethod := r.Form.Get("code_challenge_method")
+
+		if codeChallengeMethod == "" {
+			codeChallengeMethod = codeChallengeMethodPlain
+		}
+		if codeChallengeMethod != codeChallengeMethodS256 && codeChallengeMethod != codeChallengeMethodPlain {
+			description := fmt.Sprintf("Unsupported PKCE challenge method (%q).", codeChallengeMethod)
+			s.tokenErrHelper(w, errInvalidRequest, description, http.StatusBadRequest)
+			return
+		}
 
 		s.logger.Infof("Received device request for client %v with scopes %v", clientID, scopes)
 
@@ -108,6 +119,10 @@ func (s *Server) handleDeviceCode(w http.ResponseWriter, r *http.Request) {
 			Expiry:              expireTime,
 			LastRequestTime:     s.now(),
 			PollIntervalSeconds: 0,
+			PKCE: storage.PKCE{
+				CodeChallenge:       codeChallenge,
+				CodeChallengeMethod: codeChallengeMethod,
+			},
 		}
 
 		if err := s.storage.CreateDeviceToken(deviceToken); err != nil {
@@ -236,6 +251,30 @@ func (s *Server) handleDeviceToken(w http.ResponseWriter, r *http.Request) {
 			s.tokenErrHelper(w, deviceTokenPending, "", http.StatusUnauthorized)
 		}
 	case deviceTokenComplete:
+		codeChallengeFromStorage := deviceToken.PKCE.CodeChallenge
+		providedCodeVerifier := r.Form.Get("code_verifier")
+
+		switch {
+		case providedCodeVerifier != "" && codeChallengeFromStorage != "":
+			calculatedCodeChallenge, err := s.calculateCodeChallenge(providedCodeVerifier, deviceToken.PKCE.CodeChallengeMethod)
+			if err != nil {
+				s.logger.Error(err)
+				s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
+				return
+			}
+			if codeChallengeFromStorage != calculatedCodeChallenge {
+				s.tokenErrHelper(w, errInvalidGrant, "Invalid code_verifier.", http.StatusBadRequest)
+				return
+			}
+		case providedCodeVerifier != "":
+			// Received no code_challenge on /auth, but a code_verifier on /token
+			s.tokenErrHelper(w, errInvalidRequest, "No PKCE flow started. Cannot check code_verifier.", http.StatusBadRequest)
+			return
+		case codeChallengeFromStorage != "":
+			// Received PKCE request on /auth, but no code_verifier on /token
+			s.tokenErrHelper(w, errInvalidGrant, "Expecting parameter code_verifier in PKCE flow.", http.StatusBadRequest)
+			return
+		}
 		w.Write([]byte(deviceToken.Token))
 	}
 }
diff --git a/server/deviceflowhandlers_test.go b/server/deviceflowhandlers_test.go
index 225703a4..9a9f2858 100644
--- a/server/deviceflowhandlers_test.go
+++ b/server/deviceflowhandlers_test.go
@@ -49,6 +49,7 @@ func TestHandleDeviceCode(t *testing.T) {
 	tests := []struct {
 		testName               string
 		clientID               string
+		codeChallengeMethod    string
 		requestType            string
 		scopes                 []string
 		expectedResponseCode   int
@@ -71,6 +72,24 @@ func TestHandleDeviceCode(t *testing.T) {
 			expectedResponseCode: http.StatusBadRequest,
 			expectedContentType:  "application/json",
 		},
+		{
+			testName:             "New Code with valid PKCE",
+			clientID:             "test",
+			requestType:          "POST",
+			scopes:               []string{"openid", "profile", "email"},
+			codeChallengeMethod:  "S256",
+			expectedResponseCode: http.StatusOK,
+			expectedContentType:  "application/json",
+		},
+		{
+			testName:             "Invalid code challenge method",
+			clientID:             "test",
+			requestType:          "POST",
+			codeChallengeMethod:  "invalid",
+			scopes:               []string{"openid", "profile", "email"},
+			expectedResponseCode: http.StatusBadRequest,
+			expectedContentType:  "application/json",
+		},
 	}
 	for _, tc := range tests {
 		t.Run(tc.testName, func(t *testing.T) {
@@ -92,6 +111,7 @@ func TestHandleDeviceCode(t *testing.T) {
 
 			data := url.Values{}
 			data.Set("client_id", tc.clientID)
+			data.Set("code_challenge_method", tc.codeChallengeMethod)
 			for _, scope := range tc.scopes {
 				data.Add("scope", scope)
 			}
@@ -401,6 +421,13 @@ func TestDeviceTokenResponse(t *testing.T) {
 
 	now := func() time.Time { return t0 }
 
+	// Base PKCE values
+	// base64-urlencoded, sha256 digest of code_verifier
+	codeChallenge := "L7ZqsT_zNwvrH8E7J0CqPHx1wgBaFiaE-fAZcKUUAbc"
+	codeChallengeMethod := "S256"
+	// "random" string between 43 & 128 ASCII characters
+	codeVerifier := "66114650f56cc45dee7ee03c49f048ddf9aa53cbf5b09985832fa4f790ff2604"
+
 	baseDeviceRequest := storage.DeviceRequest{
 		UserCode:   "ABCD-WXYZ",
 		DeviceCode: "foo",
@@ -415,6 +442,7 @@ func TestDeviceTokenResponse(t *testing.T) {
 		testDeviceToken        storage.DeviceToken
 		testGrantType          string
 		testDeviceCode         string
+		testCodeVerifier       string
 		expectedServerResponse string
 		expectedResponseCode   int
 	}{
@@ -524,6 +552,101 @@ func TestDeviceTokenResponse(t *testing.T) {
 			expectedServerResponse: "{\"access_token\": \"foobar\"}",
 			expectedResponseCode:   http.StatusOK,
 		},
+		{
+			testName: "Successful Exchange with PKCE",
+			testDeviceToken: storage.DeviceToken{
+				DeviceCode:          "foo",
+				Status:              deviceTokenComplete,
+				Token:               "{\"access_token\": \"foobar\"}",
+				Expiry:              now().Add(5 * time.Minute),
+				LastRequestTime:     time.Time{},
+				PollIntervalSeconds: 0,
+				PKCE: storage.PKCE{
+					CodeChallenge:       codeChallenge,
+					CodeChallengeMethod: codeChallengeMethod,
+				},
+			},
+			testDeviceCode:         "foo",
+			testCodeVerifier:       codeVerifier,
+			testDeviceRequest:      baseDeviceRequest,
+			expectedServerResponse: "{\"access_token\": \"foobar\"}",
+			expectedResponseCode:   http.StatusOK,
+		},
+		{
+			testName: "Test Exchange started with PKCE but without verifier provided",
+			testDeviceToken: storage.DeviceToken{
+				DeviceCode:          "foo",
+				Status:              deviceTokenComplete,
+				Token:               "{\"access_token\": \"foobar\"}",
+				Expiry:              now().Add(5 * time.Minute),
+				LastRequestTime:     time.Time{},
+				PollIntervalSeconds: 0,
+				PKCE: storage.PKCE{
+					CodeChallenge:       codeChallenge,
+					CodeChallengeMethod: codeChallengeMethod,
+				},
+			},
+			testDeviceCode:         "foo",
+			testDeviceRequest:      baseDeviceRequest,
+			expectedServerResponse: errInvalidGrant,
+			expectedResponseCode:   http.StatusBadRequest,
+		},
+		{
+			testName: "Test Exchange not started with PKCE but verifier provided",
+			testDeviceToken: storage.DeviceToken{
+				DeviceCode:          "foo",
+				Status:              deviceTokenComplete,
+				Token:               "{\"access_token\": \"foobar\"}",
+				Expiry:              now().Add(5 * time.Minute),
+				LastRequestTime:     time.Time{},
+				PollIntervalSeconds: 0,
+			},
+			testDeviceCode:         "foo",
+			testCodeVerifier:       codeVerifier,
+			testDeviceRequest:      baseDeviceRequest,
+			expectedServerResponse: errInvalidRequest,
+			expectedResponseCode:   http.StatusBadRequest,
+		},
+		{
+			testName: "Test with PKCE but incorrect verifier provided",
+			testDeviceToken: storage.DeviceToken{
+				DeviceCode:          "foo",
+				Status:              deviceTokenComplete,
+				Token:               "{\"access_token\": \"foobar\"}",
+				Expiry:              now().Add(5 * time.Minute),
+				LastRequestTime:     time.Time{},
+				PollIntervalSeconds: 0,
+				PKCE: storage.PKCE{
+					CodeChallenge:       codeChallenge,
+					CodeChallengeMethod: codeChallengeMethod,
+				},
+			},
+			testDeviceCode:         "foo",
+			testCodeVerifier:       "invalid",
+			testDeviceRequest:      baseDeviceRequest,
+			expectedServerResponse: errInvalidGrant,
+			expectedResponseCode:   http.StatusBadRequest,
+		},
+		{
+			testName: "Test with PKCE but incorrect challenge provided",
+			testDeviceToken: storage.DeviceToken{
+				DeviceCode:          "foo",
+				Status:              deviceTokenComplete,
+				Token:               "{\"access_token\": \"foobar\"}",
+				Expiry:              now().Add(5 * time.Minute),
+				LastRequestTime:     time.Time{},
+				PollIntervalSeconds: 0,
+				PKCE: storage.PKCE{
+					CodeChallenge:       "invalid",
+					CodeChallengeMethod: codeChallengeMethod,
+				},
+			},
+			testDeviceCode:         "foo",
+			testCodeVerifier:       codeVerifier,
+			testDeviceRequest:      baseDeviceRequest,
+			expectedServerResponse: errInvalidGrant,
+			expectedResponseCode:   http.StatusBadRequest,
+		},
 	}
 	for _, tc := range tests {
 		t.Run(tc.testName, func(t *testing.T) {
@@ -558,6 +681,9 @@ func TestDeviceTokenResponse(t *testing.T) {
 			}
 			data.Set("grant_type", grantType)
 			data.Set("device_code", tc.testDeviceCode)
+			if tc.testCodeVerifier != "" {
+				data.Set("code_verifier", tc.testCodeVerifier)
+			}
 			req, _ := http.NewRequest("POST", u.String(), bytes.NewBufferString(data.Encode()))
 			req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
 
diff --git a/storage/conformance/conformance.go b/storage/conformance/conformance.go
index 4e927e8f..1b45b76c 100644
--- a/storage/conformance/conformance.go
+++ b/storage/conformance/conformance.go
@@ -893,6 +893,10 @@ func testGC(t *testing.T, s storage.Storage) {
 		Expiry:              expiry,
 		LastRequestTime:     time.Now(),
 		PollIntervalSeconds: 0,
+		PKCE: storage.PKCE{
+			CodeChallenge:       "challenge",
+			CodeChallengeMethod: "S256",
+		},
 	}
 
 	if err := s.CreateDeviceToken(dt); err != nil {
@@ -992,6 +996,11 @@ func testDeviceRequestCRUD(t *testing.T, s storage.Storage) {
 }
 
 func testDeviceTokenCRUD(t *testing.T, s storage.Storage) {
+	codeChallenge := storage.PKCE{
+		CodeChallenge:       "code_challenge_test",
+		CodeChallengeMethod: "plain",
+	}
+
 	// Create a Token
 	d1 := storage.DeviceToken{
 		DeviceCode:          storage.NewID(),
@@ -1000,6 +1009,7 @@ func testDeviceTokenCRUD(t *testing.T, s storage.Storage) {
 		Expiry:              neverExpire,
 		LastRequestTime:     time.Now(),
 		PollIntervalSeconds: 0,
+		PKCE:                codeChallenge,
 	}
 
 	if err := s.CreateDeviceToken(d1); err != nil {
@@ -1032,4 +1042,7 @@ func testDeviceTokenCRUD(t *testing.T, s storage.Storage) {
 	if got.Token != "token data" {
 		t.Fatalf("update failed, wanted token %v got %v", "token data", got.Token)
 	}
+	if !reflect.DeepEqual(got.PKCE, codeChallenge) {
+		t.Fatalf("storage does not support PKCE, wanted challenge=%#v got %#v", codeChallenge, got.PKCE)
+	}
 }
diff --git a/storage/ent/client/devicetoken.go b/storage/ent/client/devicetoken.go
index d8870787..99cf077d 100644
--- a/storage/ent/client/devicetoken.go
+++ b/storage/ent/client/devicetoken.go
@@ -17,6 +17,8 @@ func (d *Database) CreateDeviceToken(token storage.DeviceToken) error {
 		SetExpiry(token.Expiry.UTC()).
 		SetLastRequest(token.LastRequestTime.UTC()).
 		SetStatus(token.Status).
+		SetCodeChallenge(token.PKCE.CodeChallenge).
+		SetCodeChallengeMethod(token.PKCE.CodeChallengeMethod).
 		Save(context.TODO())
 	if err != nil {
 		return convertDBError("create device token: %w", err)
@@ -63,6 +65,8 @@ func (d *Database) UpdateDeviceToken(deviceCode string, updater func(old storage
 		SetExpiry(newToken.Expiry.UTC()).
 		SetLastRequest(newToken.LastRequestTime.UTC()).
 		SetStatus(newToken.Status).
+		SetCodeChallenge(newToken.PKCE.CodeChallenge).
+		SetCodeChallengeMethod(newToken.PKCE.CodeChallengeMethod).
 		Save(context.TODO())
 	if err != nil {
 		return rollback(tx, "update device token uploading: %w", err)
diff --git a/storage/ent/client/types.go b/storage/ent/client/types.go
index ada9058e..397d4d30 100644
--- a/storage/ent/client/types.go
+++ b/storage/ent/client/types.go
@@ -165,5 +165,9 @@ func toStorageDeviceToken(t *db.DeviceToken) storage.DeviceToken {
 		Expiry:              t.Expiry,
 		LastRequestTime:     t.LastRequest,
 		PollIntervalSeconds: t.PollInterval,
+		PKCE: storage.PKCE{
+			CodeChallenge:       t.CodeChallenge,
+			CodeChallengeMethod: t.CodeChallengeMethod,
+		},
 	}
 }
diff --git a/storage/ent/db/authcode.go b/storage/ent/db/authcode.go
index 9af0ee3b..6ddbeb57 100644
--- a/storage/ent/db/authcode.go
+++ b/storage/ent/db/authcode.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -192,11 +192,11 @@ func (ac *AuthCode) Update() *AuthCodeUpdateOne {
 // Unwrap unwraps the AuthCode entity that was returned from a transaction after it was closed,
 // so that all future queries will be executed through the driver which created the transaction.
 func (ac *AuthCode) Unwrap() *AuthCode {
-	tx, ok := ac.config.driver.(*txDriver)
+	_tx, ok := ac.config.driver.(*txDriver)
 	if !ok {
 		panic("db: AuthCode is not a transactional entity")
 	}
-	ac.config.driver = tx.drv
+	ac.config.driver = _tx.drv
 	return ac
 }
 
@@ -204,38 +204,52 @@ func (ac *AuthCode) Unwrap() *AuthCode {
 func (ac *AuthCode) String() string {
 	var builder strings.Builder
 	builder.WriteString("AuthCode(")
-	builder.WriteString(fmt.Sprintf("id=%v", ac.ID))
-	builder.WriteString(", client_id=")
+	builder.WriteString(fmt.Sprintf("id=%v, ", ac.ID))
+	builder.WriteString("client_id=")
 	builder.WriteString(ac.ClientID)
-	builder.WriteString(", scopes=")
+	builder.WriteString(", ")
+	builder.WriteString("scopes=")
 	builder.WriteString(fmt.Sprintf("%v", ac.Scopes))
-	builder.WriteString(", nonce=")
+	builder.WriteString(", ")
+	builder.WriteString("nonce=")
 	builder.WriteString(ac.Nonce)
-	builder.WriteString(", redirect_uri=")
+	builder.WriteString(", ")
+	builder.WriteString("redirect_uri=")
 	builder.WriteString(ac.RedirectURI)
-	builder.WriteString(", claims_user_id=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_user_id=")
 	builder.WriteString(ac.ClaimsUserID)
-	builder.WriteString(", claims_username=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_username=")
 	builder.WriteString(ac.ClaimsUsername)
-	builder.WriteString(", claims_email=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_email=")
 	builder.WriteString(ac.ClaimsEmail)
-	builder.WriteString(", claims_email_verified=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_email_verified=")
 	builder.WriteString(fmt.Sprintf("%v", ac.ClaimsEmailVerified))
-	builder.WriteString(", claims_groups=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_groups=")
 	builder.WriteString(fmt.Sprintf("%v", ac.ClaimsGroups))
-	builder.WriteString(", claims_preferred_username=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_preferred_username=")
 	builder.WriteString(ac.ClaimsPreferredUsername)
-	builder.WriteString(", connector_id=")
+	builder.WriteString(", ")
+	builder.WriteString("connector_id=")
 	builder.WriteString(ac.ConnectorID)
+	builder.WriteString(", ")
 	if v := ac.ConnectorData; v != nil {
-		builder.WriteString(", connector_data=")
+		builder.WriteString("connector_data=")
 		builder.WriteString(fmt.Sprintf("%v", *v))
 	}
-	builder.WriteString(", expiry=")
+	builder.WriteString(", ")
+	builder.WriteString("expiry=")
 	builder.WriteString(ac.Expiry.Format(time.ANSIC))
-	builder.WriteString(", code_challenge=")
+	builder.WriteString(", ")
+	builder.WriteString("code_challenge=")
 	builder.WriteString(ac.CodeChallenge)
-	builder.WriteString(", code_challenge_method=")
+	builder.WriteString(", ")
+	builder.WriteString("code_challenge_method=")
 	builder.WriteString(ac.CodeChallengeMethod)
 	builder.WriteByte(')')
 	return builder.String()
diff --git a/storage/ent/db/authcode/authcode.go b/storage/ent/db/authcode/authcode.go
index 3411f15b..b78eb970 100644
--- a/storage/ent/db/authcode/authcode.go
+++ b/storage/ent/db/authcode/authcode.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package authcode
 
diff --git a/storage/ent/db/authcode/where.go b/storage/ent/db/authcode/where.go
index 0b9a37ef..be1954d7 100644
--- a/storage/ent/db/authcode/where.go
+++ b/storage/ent/db/authcode/where.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package authcode
 
@@ -33,12 +33,6 @@ func IDNEQ(id string) predicate.AuthCode {
 // IDIn applies the In predicate on the ID field.
 func IDIn(ids ...string) predicate.AuthCode {
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -50,12 +44,6 @@ func IDIn(ids ...string) predicate.AuthCode {
 // IDNotIn applies the NotIn predicate on the ID field.
 func IDNotIn(ids ...string) predicate.AuthCode {
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -204,12 +192,6 @@ func ClientIDIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClientID), v...))
 	})
 }
@@ -221,12 +203,6 @@ func ClientIDNotIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClientID), v...))
 	})
 }
@@ -329,12 +305,6 @@ func NonceIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldNonce), v...))
 	})
 }
@@ -346,12 +316,6 @@ func NonceNotIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldNonce), v...))
 	})
 }
@@ -440,12 +404,6 @@ func RedirectURIIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldRedirectURI), v...))
 	})
 }
@@ -457,12 +415,6 @@ func RedirectURINotIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldRedirectURI), v...))
 	})
 }
@@ -551,12 +503,6 @@ func ClaimsUserIDIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClaimsUserID), v...))
 	})
 }
@@ -568,12 +514,6 @@ func ClaimsUserIDNotIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClaimsUserID), v...))
 	})
 }
@@ -662,12 +602,6 @@ func ClaimsUsernameIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClaimsUsername), v...))
 	})
 }
@@ -679,12 +613,6 @@ func ClaimsUsernameNotIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClaimsUsername), v...))
 	})
 }
@@ -773,12 +701,6 @@ func ClaimsEmailIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClaimsEmail), v...))
 	})
 }
@@ -790,12 +712,6 @@ func ClaimsEmailNotIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClaimsEmail), v...))
 	})
 }
@@ -912,12 +828,6 @@ func ClaimsPreferredUsernameIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClaimsPreferredUsername), v...))
 	})
 }
@@ -929,12 +839,6 @@ func ClaimsPreferredUsernameNotIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClaimsPreferredUsername), v...))
 	})
 }
@@ -1023,12 +927,6 @@ func ConnectorIDIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldConnectorID), v...))
 	})
 }
@@ -1040,12 +938,6 @@ func ConnectorIDNotIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldConnectorID), v...))
 	})
 }
@@ -1134,12 +1026,6 @@ func ConnectorDataIn(vs ...[]byte) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldConnectorData), v...))
 	})
 }
@@ -1151,12 +1037,6 @@ func ConnectorDataNotIn(vs ...[]byte) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldConnectorData), v...))
 	})
 }
@@ -1224,12 +1104,6 @@ func ExpiryIn(vs ...time.Time) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldExpiry), v...))
 	})
 }
@@ -1241,12 +1115,6 @@ func ExpiryNotIn(vs ...time.Time) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldExpiry), v...))
 	})
 }
@@ -1300,12 +1168,6 @@ func CodeChallengeIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldCodeChallenge), v...))
 	})
 }
@@ -1317,12 +1179,6 @@ func CodeChallengeNotIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldCodeChallenge), v...))
 	})
 }
@@ -1411,12 +1267,6 @@ func CodeChallengeMethodIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldCodeChallengeMethod), v...))
 	})
 }
@@ -1428,12 +1278,6 @@ func CodeChallengeMethodNotIn(vs ...string) predicate.AuthCode {
 		v[i] = vs[i]
 	}
 	return predicate.AuthCode(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldCodeChallengeMethod), v...))
 	})
 }
diff --git a/storage/ent/db/authcode_create.go b/storage/ent/db/authcode_create.go
index 23b34300..c075c3d3 100644
--- a/storage/ent/db/authcode_create.go
+++ b/storage/ent/db/authcode_create.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -180,9 +180,15 @@ func (acc *AuthCodeCreate) Save(ctx context.Context) (*AuthCode, error) {
 			}
 			mut = acc.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, acc.mutation); err != nil {
+		v, err := mut.Mutate(ctx, acc.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*AuthCode)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from AuthCodeMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -310,7 +316,7 @@ func (acc *AuthCodeCreate) sqlSave(ctx context.Context) (*AuthCode, error) {
 	_node, _spec := acc.createSpec()
 	if err := sqlgraph.CreateNode(ctx, acc.driver, _spec); err != nil {
 		if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
@@ -495,7 +501,7 @@ func (accb *AuthCodeCreateBulk) Save(ctx context.Context) ([]*AuthCode, error) {
 					// Invoke the actual operation on the latest mutation in the chain.
 					if err = sqlgraph.BatchCreate(ctx, accb.driver, spec); err != nil {
 						if sqlgraph.IsConstraintError(err) {
-							err = &ConstraintError{err.Error(), err}
+							err = &ConstraintError{msg: err.Error(), wrap: err}
 						}
 					}
 				}
diff --git a/storage/ent/db/authcode_delete.go b/storage/ent/db/authcode_delete.go
index 9b657236..3471394a 100644
--- a/storage/ent/db/authcode_delete.go
+++ b/storage/ent/db/authcode_delete.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -84,7 +84,11 @@ func (acd *AuthCodeDelete) sqlExec(ctx context.Context) (int, error) {
 			}
 		}
 	}
-	return sqlgraph.DeleteNodes(ctx, acd.driver, _spec)
+	affected, err := sqlgraph.DeleteNodes(ctx, acd.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	return affected, err
 }
 
 // AuthCodeDeleteOne is the builder for deleting a single AuthCode entity.
diff --git a/storage/ent/db/authcode_query.go b/storage/ent/db/authcode_query.go
index 452b9847..a82a4506 100644
--- a/storage/ent/db/authcode_query.go
+++ b/storage/ent/db/authcode_query.go
@@ -1,10 +1,9 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"math"
 
@@ -264,15 +263,17 @@ func (acq *AuthCodeQuery) Clone() *AuthCodeQuery {
 //		Scan(ctx, &v)
 //
 func (acq *AuthCodeQuery) GroupBy(field string, fields ...string) *AuthCodeGroupBy {
-	group := &AuthCodeGroupBy{config: acq.config}
-	group.fields = append([]string{field}, fields...)
-	group.path = func(ctx context.Context) (prev *sql.Selector, err error) {
+	grbuild := &AuthCodeGroupBy{config: acq.config}
+	grbuild.fields = append([]string{field}, fields...)
+	grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
 		if err := acq.prepareQuery(ctx); err != nil {
 			return nil, err
 		}
 		return acq.sqlQuery(ctx), nil
 	}
-	return group
+	grbuild.label = authcode.Label
+	grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
+	return grbuild
 }
 
 // Select allows the selection one or more fields/columns for the given query,
@@ -290,7 +291,10 @@ func (acq *AuthCodeQuery) GroupBy(field string, fields ...string) *AuthCodeGroup
 //
 func (acq *AuthCodeQuery) Select(fields ...string) *AuthCodeSelect {
 	acq.fields = append(acq.fields, fields...)
-	return &AuthCodeSelect{AuthCodeQuery: acq}
+	selbuild := &AuthCodeSelect{AuthCodeQuery: acq}
+	selbuild.label = authcode.Label
+	selbuild.flds, selbuild.scan = &acq.fields, selbuild.Scan
+	return selbuild
 }
 
 func (acq *AuthCodeQuery) prepareQuery(ctx context.Context) error {
@@ -309,23 +313,22 @@ func (acq *AuthCodeQuery) prepareQuery(ctx context.Context) error {
 	return nil
 }
 
-func (acq *AuthCodeQuery) sqlAll(ctx context.Context) ([]*AuthCode, error) {
+func (acq *AuthCodeQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*AuthCode, error) {
 	var (
 		nodes = []*AuthCode{}
 		_spec = acq.querySpec()
 	)
 	_spec.ScanValues = func(columns []string) ([]interface{}, error) {
-		node := &AuthCode{config: acq.config}
-		nodes = append(nodes, node)
-		return node.scanValues(columns)
+		return (*AuthCode).scanValues(nil, columns)
 	}
 	_spec.Assign = func(columns []string, values []interface{}) error {
-		if len(nodes) == 0 {
-			return fmt.Errorf("db: Assign called without calling ScanValues")
-		}
-		node := nodes[len(nodes)-1]
+		node := &AuthCode{config: acq.config}
+		nodes = append(nodes, node)
 		return node.assignValues(columns, values)
 	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
 	if err := sqlgraph.QueryNodes(ctx, acq.driver, _spec); err != nil {
 		return nil, err
 	}
@@ -435,6 +438,7 @@ func (acq *AuthCodeQuery) sqlQuery(ctx context.Context) *sql.Selector {
 // AuthCodeGroupBy is the group-by builder for AuthCode entities.
 type AuthCodeGroupBy struct {
 	config
+	selector
 	fields []string
 	fns    []AggregateFunc
 	// intermediate query (i.e. traversal path).
@@ -458,209 +462,6 @@ func (acgb *AuthCodeGroupBy) Scan(ctx context.Context, v interface{}) error {
 	return acgb.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (acgb *AuthCodeGroupBy) ScanX(ctx context.Context, v interface{}) {
-	if err := acgb.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (acgb *AuthCodeGroupBy) Strings(ctx context.Context) ([]string, error) {
-	if len(acgb.fields) > 1 {
-		return nil, errors.New("db: AuthCodeGroupBy.Strings is not achievable when grouping more than 1 field")
-	}
-	var v []string
-	if err := acgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (acgb *AuthCodeGroupBy) StringsX(ctx context.Context) []string {
-	v, err := acgb.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (acgb *AuthCodeGroupBy) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = acgb.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authcode.Label}
-	default:
-		err = fmt.Errorf("db: AuthCodeGroupBy.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (acgb *AuthCodeGroupBy) StringX(ctx context.Context) string {
-	v, err := acgb.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (acgb *AuthCodeGroupBy) Ints(ctx context.Context) ([]int, error) {
-	if len(acgb.fields) > 1 {
-		return nil, errors.New("db: AuthCodeGroupBy.Ints is not achievable when grouping more than 1 field")
-	}
-	var v []int
-	if err := acgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (acgb *AuthCodeGroupBy) IntsX(ctx context.Context) []int {
-	v, err := acgb.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (acgb *AuthCodeGroupBy) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = acgb.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authcode.Label}
-	default:
-		err = fmt.Errorf("db: AuthCodeGroupBy.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (acgb *AuthCodeGroupBy) IntX(ctx context.Context) int {
-	v, err := acgb.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (acgb *AuthCodeGroupBy) Float64s(ctx context.Context) ([]float64, error) {
-	if len(acgb.fields) > 1 {
-		return nil, errors.New("db: AuthCodeGroupBy.Float64s is not achievable when grouping more than 1 field")
-	}
-	var v []float64
-	if err := acgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (acgb *AuthCodeGroupBy) Float64sX(ctx context.Context) []float64 {
-	v, err := acgb.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (acgb *AuthCodeGroupBy) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = acgb.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authcode.Label}
-	default:
-		err = fmt.Errorf("db: AuthCodeGroupBy.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (acgb *AuthCodeGroupBy) Float64X(ctx context.Context) float64 {
-	v, err := acgb.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (acgb *AuthCodeGroupBy) Bools(ctx context.Context) ([]bool, error) {
-	if len(acgb.fields) > 1 {
-		return nil, errors.New("db: AuthCodeGroupBy.Bools is not achievable when grouping more than 1 field")
-	}
-	var v []bool
-	if err := acgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (acgb *AuthCodeGroupBy) BoolsX(ctx context.Context) []bool {
-	v, err := acgb.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (acgb *AuthCodeGroupBy) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = acgb.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authcode.Label}
-	default:
-		err = fmt.Errorf("db: AuthCodeGroupBy.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (acgb *AuthCodeGroupBy) BoolX(ctx context.Context) bool {
-	v, err := acgb.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (acgb *AuthCodeGroupBy) sqlScan(ctx context.Context, v interface{}) error {
 	for _, f := range acgb.fields {
 		if !authcode.ValidColumn(f) {
@@ -702,6 +503,7 @@ func (acgb *AuthCodeGroupBy) sqlQuery() *sql.Selector {
 // AuthCodeSelect is the builder for selecting fields of AuthCode entities.
 type AuthCodeSelect struct {
 	*AuthCodeQuery
+	selector
 	// intermediate query (i.e. traversal path).
 	sql *sql.Selector
 }
@@ -715,201 +517,6 @@ func (acs *AuthCodeSelect) Scan(ctx context.Context, v interface{}) error {
 	return acs.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (acs *AuthCodeSelect) ScanX(ctx context.Context, v interface{}) {
-	if err := acs.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from a selector. It is only allowed when selecting one field.
-func (acs *AuthCodeSelect) Strings(ctx context.Context) ([]string, error) {
-	if len(acs.fields) > 1 {
-		return nil, errors.New("db: AuthCodeSelect.Strings is not achievable when selecting more than 1 field")
-	}
-	var v []string
-	if err := acs.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (acs *AuthCodeSelect) StringsX(ctx context.Context) []string {
-	v, err := acs.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a selector. It is only allowed when selecting one field.
-func (acs *AuthCodeSelect) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = acs.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authcode.Label}
-	default:
-		err = fmt.Errorf("db: AuthCodeSelect.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (acs *AuthCodeSelect) StringX(ctx context.Context) string {
-	v, err := acs.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from a selector. It is only allowed when selecting one field.
-func (acs *AuthCodeSelect) Ints(ctx context.Context) ([]int, error) {
-	if len(acs.fields) > 1 {
-		return nil, errors.New("db: AuthCodeSelect.Ints is not achievable when selecting more than 1 field")
-	}
-	var v []int
-	if err := acs.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (acs *AuthCodeSelect) IntsX(ctx context.Context) []int {
-	v, err := acs.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a selector. It is only allowed when selecting one field.
-func (acs *AuthCodeSelect) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = acs.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authcode.Label}
-	default:
-		err = fmt.Errorf("db: AuthCodeSelect.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (acs *AuthCodeSelect) IntX(ctx context.Context) int {
-	v, err := acs.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
-func (acs *AuthCodeSelect) Float64s(ctx context.Context) ([]float64, error) {
-	if len(acs.fields) > 1 {
-		return nil, errors.New("db: AuthCodeSelect.Float64s is not achievable when selecting more than 1 field")
-	}
-	var v []float64
-	if err := acs.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (acs *AuthCodeSelect) Float64sX(ctx context.Context) []float64 {
-	v, err := acs.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
-func (acs *AuthCodeSelect) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = acs.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authcode.Label}
-	default:
-		err = fmt.Errorf("db: AuthCodeSelect.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (acs *AuthCodeSelect) Float64X(ctx context.Context) float64 {
-	v, err := acs.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from a selector. It is only allowed when selecting one field.
-func (acs *AuthCodeSelect) Bools(ctx context.Context) ([]bool, error) {
-	if len(acs.fields) > 1 {
-		return nil, errors.New("db: AuthCodeSelect.Bools is not achievable when selecting more than 1 field")
-	}
-	var v []bool
-	if err := acs.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (acs *AuthCodeSelect) BoolsX(ctx context.Context) []bool {
-	v, err := acs.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a selector. It is only allowed when selecting one field.
-func (acs *AuthCodeSelect) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = acs.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authcode.Label}
-	default:
-		err = fmt.Errorf("db: AuthCodeSelect.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (acs *AuthCodeSelect) BoolX(ctx context.Context) bool {
-	v, err := acs.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (acs *AuthCodeSelect) sqlScan(ctx context.Context, v interface{}) error {
 	rows := &sql.Rows{}
 	query, args := acs.sql.Query()
diff --git a/storage/ent/db/authcode_update.go b/storage/ent/db/authcode_update.go
index ccd0eee8..5d9764bc 100644
--- a/storage/ent/db/authcode_update.go
+++ b/storage/ent/db/authcode_update.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -410,7 +410,7 @@ func (acu *AuthCodeUpdate) sqlSave(ctx context.Context) (n int, err error) {
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{authcode.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return 0, err
 	}
@@ -600,9 +600,15 @@ func (acuo *AuthCodeUpdateOne) Save(ctx context.Context) (*AuthCode, error) {
 			}
 			mut = acuo.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, acuo.mutation); err != nil {
+		v, err := mut.Mutate(ctx, acuo.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*AuthCode)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from AuthCodeMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -834,7 +840,7 @@ func (acuo *AuthCodeUpdateOne) sqlSave(ctx context.Context) (_node *AuthCode, er
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{authcode.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
diff --git a/storage/ent/db/authrequest.go b/storage/ent/db/authrequest.go
index e225476a..095427ae 100644
--- a/storage/ent/db/authrequest.go
+++ b/storage/ent/db/authrequest.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -234,11 +234,11 @@ func (ar *AuthRequest) Update() *AuthRequestUpdateOne {
 // Unwrap unwraps the AuthRequest entity that was returned from a transaction after it was closed,
 // so that all future queries will be executed through the driver which created the transaction.
 func (ar *AuthRequest) Unwrap() *AuthRequest {
-	tx, ok := ar.config.driver.(*txDriver)
+	_tx, ok := ar.config.driver.(*txDriver)
 	if !ok {
 		panic("db: AuthRequest is not a transactional entity")
 	}
-	ar.config.driver = tx.drv
+	ar.config.driver = _tx.drv
 	return ar
 }
 
@@ -246,46 +246,64 @@ func (ar *AuthRequest) Unwrap() *AuthRequest {
 func (ar *AuthRequest) String() string {
 	var builder strings.Builder
 	builder.WriteString("AuthRequest(")
-	builder.WriteString(fmt.Sprintf("id=%v", ar.ID))
-	builder.WriteString(", client_id=")
+	builder.WriteString(fmt.Sprintf("id=%v, ", ar.ID))
+	builder.WriteString("client_id=")
 	builder.WriteString(ar.ClientID)
-	builder.WriteString(", scopes=")
+	builder.WriteString(", ")
+	builder.WriteString("scopes=")
 	builder.WriteString(fmt.Sprintf("%v", ar.Scopes))
-	builder.WriteString(", response_types=")
+	builder.WriteString(", ")
+	builder.WriteString("response_types=")
 	builder.WriteString(fmt.Sprintf("%v", ar.ResponseTypes))
-	builder.WriteString(", redirect_uri=")
+	builder.WriteString(", ")
+	builder.WriteString("redirect_uri=")
 	builder.WriteString(ar.RedirectURI)
-	builder.WriteString(", nonce=")
+	builder.WriteString(", ")
+	builder.WriteString("nonce=")
 	builder.WriteString(ar.Nonce)
-	builder.WriteString(", state=")
+	builder.WriteString(", ")
+	builder.WriteString("state=")
 	builder.WriteString(ar.State)
-	builder.WriteString(", force_approval_prompt=")
+	builder.WriteString(", ")
+	builder.WriteString("force_approval_prompt=")
 	builder.WriteString(fmt.Sprintf("%v", ar.ForceApprovalPrompt))
-	builder.WriteString(", logged_in=")
+	builder.WriteString(", ")
+	builder.WriteString("logged_in=")
 	builder.WriteString(fmt.Sprintf("%v", ar.LoggedIn))
-	builder.WriteString(", claims_user_id=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_user_id=")
 	builder.WriteString(ar.ClaimsUserID)
-	builder.WriteString(", claims_username=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_username=")
 	builder.WriteString(ar.ClaimsUsername)
-	builder.WriteString(", claims_email=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_email=")
 	builder.WriteString(ar.ClaimsEmail)
-	builder.WriteString(", claims_email_verified=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_email_verified=")
 	builder.WriteString(fmt.Sprintf("%v", ar.ClaimsEmailVerified))
-	builder.WriteString(", claims_groups=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_groups=")
 	builder.WriteString(fmt.Sprintf("%v", ar.ClaimsGroups))
-	builder.WriteString(", claims_preferred_username=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_preferred_username=")
 	builder.WriteString(ar.ClaimsPreferredUsername)
-	builder.WriteString(", connector_id=")
+	builder.WriteString(", ")
+	builder.WriteString("connector_id=")
 	builder.WriteString(ar.ConnectorID)
+	builder.WriteString(", ")
 	if v := ar.ConnectorData; v != nil {
-		builder.WriteString(", connector_data=")
+		builder.WriteString("connector_data=")
 		builder.WriteString(fmt.Sprintf("%v", *v))
 	}
-	builder.WriteString(", expiry=")
+	builder.WriteString(", ")
+	builder.WriteString("expiry=")
 	builder.WriteString(ar.Expiry.Format(time.ANSIC))
-	builder.WriteString(", code_challenge=")
+	builder.WriteString(", ")
+	builder.WriteString("code_challenge=")
 	builder.WriteString(ar.CodeChallenge)
-	builder.WriteString(", code_challenge_method=")
+	builder.WriteString(", ")
+	builder.WriteString("code_challenge_method=")
 	builder.WriteString(ar.CodeChallengeMethod)
 	builder.WriteString(", hmac_key=")
 	builder.WriteString(fmt.Sprintf("%v", ar.HmacKey))
diff --git a/storage/ent/db/authrequest/authrequest.go b/storage/ent/db/authrequest/authrequest.go
index ae589e11..537f631e 100644
--- a/storage/ent/db/authrequest/authrequest.go
+++ b/storage/ent/db/authrequest/authrequest.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package authrequest
 
diff --git a/storage/ent/db/authrequest/where.go b/storage/ent/db/authrequest/where.go
index b5a66821..1fd1d4e4 100644
--- a/storage/ent/db/authrequest/where.go
+++ b/storage/ent/db/authrequest/where.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package authrequest
 
@@ -33,12 +33,6 @@ func IDNEQ(id string) predicate.AuthRequest {
 // IDIn applies the In predicate on the ID field.
 func IDIn(ids ...string) predicate.AuthRequest {
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -50,12 +44,6 @@ func IDIn(ids ...string) predicate.AuthRequest {
 // IDNotIn applies the NotIn predicate on the ID field.
 func IDNotIn(ids ...string) predicate.AuthRequest {
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -232,12 +220,6 @@ func ClientIDIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClientID), v...))
 	})
 }
@@ -249,12 +231,6 @@ func ClientIDNotIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClientID), v...))
 	})
 }
@@ -371,12 +347,6 @@ func RedirectURIIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldRedirectURI), v...))
 	})
 }
@@ -388,12 +358,6 @@ func RedirectURINotIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldRedirectURI), v...))
 	})
 }
@@ -482,12 +446,6 @@ func NonceIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldNonce), v...))
 	})
 }
@@ -499,12 +457,6 @@ func NonceNotIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldNonce), v...))
 	})
 }
@@ -593,12 +545,6 @@ func StateIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldState), v...))
 	})
 }
@@ -610,12 +556,6 @@ func StateNotIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldState), v...))
 	})
 }
@@ -732,12 +672,6 @@ func ClaimsUserIDIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClaimsUserID), v...))
 	})
 }
@@ -749,12 +683,6 @@ func ClaimsUserIDNotIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClaimsUserID), v...))
 	})
 }
@@ -843,12 +771,6 @@ func ClaimsUsernameIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClaimsUsername), v...))
 	})
 }
@@ -860,12 +782,6 @@ func ClaimsUsernameNotIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClaimsUsername), v...))
 	})
 }
@@ -954,12 +870,6 @@ func ClaimsEmailIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClaimsEmail), v...))
 	})
 }
@@ -971,12 +881,6 @@ func ClaimsEmailNotIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClaimsEmail), v...))
 	})
 }
@@ -1093,12 +997,6 @@ func ClaimsPreferredUsernameIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClaimsPreferredUsername), v...))
 	})
 }
@@ -1110,12 +1008,6 @@ func ClaimsPreferredUsernameNotIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClaimsPreferredUsername), v...))
 	})
 }
@@ -1204,12 +1096,6 @@ func ConnectorIDIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldConnectorID), v...))
 	})
 }
@@ -1221,12 +1107,6 @@ func ConnectorIDNotIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldConnectorID), v...))
 	})
 }
@@ -1315,12 +1195,6 @@ func ConnectorDataIn(vs ...[]byte) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldConnectorData), v...))
 	})
 }
@@ -1332,12 +1206,6 @@ func ConnectorDataNotIn(vs ...[]byte) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldConnectorData), v...))
 	})
 }
@@ -1405,12 +1273,6 @@ func ExpiryIn(vs ...time.Time) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldExpiry), v...))
 	})
 }
@@ -1422,12 +1284,6 @@ func ExpiryNotIn(vs ...time.Time) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldExpiry), v...))
 	})
 }
@@ -1481,12 +1337,6 @@ func CodeChallengeIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldCodeChallenge), v...))
 	})
 }
@@ -1498,12 +1348,6 @@ func CodeChallengeNotIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldCodeChallenge), v...))
 	})
 }
@@ -1592,12 +1436,6 @@ func CodeChallengeMethodIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldCodeChallengeMethod), v...))
 	})
 }
@@ -1609,12 +1447,6 @@ func CodeChallengeMethodNotIn(vs ...string) predicate.AuthRequest {
 		v[i] = vs[i]
 	}
 	return predicate.AuthRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldCodeChallengeMethod), v...))
 	})
 }
diff --git a/storage/ent/db/authrequest_create.go b/storage/ent/db/authrequest_create.go
index 65ba4b35..c353c182 100644
--- a/storage/ent/db/authrequest_create.go
+++ b/storage/ent/db/authrequest_create.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -210,9 +210,15 @@ func (arc *AuthRequestCreate) Save(ctx context.Context) (*AuthRequest, error) {
 			}
 			mut = arc.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, arc.mutation); err != nil {
+		v, err := mut.Mutate(ctx, arc.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*AuthRequest)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from AuthRequestMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -317,7 +323,7 @@ func (arc *AuthRequestCreate) sqlSave(ctx context.Context) (*AuthRequest, error)
 	_node, _spec := arc.createSpec()
 	if err := sqlgraph.CreateNode(ctx, arc.driver, _spec); err != nil {
 		if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
@@ -542,7 +548,7 @@ func (arcb *AuthRequestCreateBulk) Save(ctx context.Context) ([]*AuthRequest, er
 					// Invoke the actual operation on the latest mutation in the chain.
 					if err = sqlgraph.BatchCreate(ctx, arcb.driver, spec); err != nil {
 						if sqlgraph.IsConstraintError(err) {
-							err = &ConstraintError{err.Error(), err}
+							err = &ConstraintError{msg: err.Error(), wrap: err}
 						}
 					}
 				}
diff --git a/storage/ent/db/authrequest_delete.go b/storage/ent/db/authrequest_delete.go
index 1e6ff754..495f4676 100644
--- a/storage/ent/db/authrequest_delete.go
+++ b/storage/ent/db/authrequest_delete.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -84,7 +84,11 @@ func (ard *AuthRequestDelete) sqlExec(ctx context.Context) (int, error) {
 			}
 		}
 	}
-	return sqlgraph.DeleteNodes(ctx, ard.driver, _spec)
+	affected, err := sqlgraph.DeleteNodes(ctx, ard.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	return affected, err
 }
 
 // AuthRequestDeleteOne is the builder for deleting a single AuthRequest entity.
diff --git a/storage/ent/db/authrequest_query.go b/storage/ent/db/authrequest_query.go
index 236b684b..577da17b 100644
--- a/storage/ent/db/authrequest_query.go
+++ b/storage/ent/db/authrequest_query.go
@@ -1,10 +1,9 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"math"
 
@@ -264,15 +263,17 @@ func (arq *AuthRequestQuery) Clone() *AuthRequestQuery {
 //		Scan(ctx, &v)
 //
 func (arq *AuthRequestQuery) GroupBy(field string, fields ...string) *AuthRequestGroupBy {
-	group := &AuthRequestGroupBy{config: arq.config}
-	group.fields = append([]string{field}, fields...)
-	group.path = func(ctx context.Context) (prev *sql.Selector, err error) {
+	grbuild := &AuthRequestGroupBy{config: arq.config}
+	grbuild.fields = append([]string{field}, fields...)
+	grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
 		if err := arq.prepareQuery(ctx); err != nil {
 			return nil, err
 		}
 		return arq.sqlQuery(ctx), nil
 	}
-	return group
+	grbuild.label = authrequest.Label
+	grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
+	return grbuild
 }
 
 // Select allows the selection one or more fields/columns for the given query,
@@ -290,7 +291,10 @@ func (arq *AuthRequestQuery) GroupBy(field string, fields ...string) *AuthReques
 //
 func (arq *AuthRequestQuery) Select(fields ...string) *AuthRequestSelect {
 	arq.fields = append(arq.fields, fields...)
-	return &AuthRequestSelect{AuthRequestQuery: arq}
+	selbuild := &AuthRequestSelect{AuthRequestQuery: arq}
+	selbuild.label = authrequest.Label
+	selbuild.flds, selbuild.scan = &arq.fields, selbuild.Scan
+	return selbuild
 }
 
 func (arq *AuthRequestQuery) prepareQuery(ctx context.Context) error {
@@ -309,23 +313,22 @@ func (arq *AuthRequestQuery) prepareQuery(ctx context.Context) error {
 	return nil
 }
 
-func (arq *AuthRequestQuery) sqlAll(ctx context.Context) ([]*AuthRequest, error) {
+func (arq *AuthRequestQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*AuthRequest, error) {
 	var (
 		nodes = []*AuthRequest{}
 		_spec = arq.querySpec()
 	)
 	_spec.ScanValues = func(columns []string) ([]interface{}, error) {
-		node := &AuthRequest{config: arq.config}
-		nodes = append(nodes, node)
-		return node.scanValues(columns)
+		return (*AuthRequest).scanValues(nil, columns)
 	}
 	_spec.Assign = func(columns []string, values []interface{}) error {
-		if len(nodes) == 0 {
-			return fmt.Errorf("db: Assign called without calling ScanValues")
-		}
-		node := nodes[len(nodes)-1]
+		node := &AuthRequest{config: arq.config}
+		nodes = append(nodes, node)
 		return node.assignValues(columns, values)
 	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
 	if err := sqlgraph.QueryNodes(ctx, arq.driver, _spec); err != nil {
 		return nil, err
 	}
@@ -435,6 +438,7 @@ func (arq *AuthRequestQuery) sqlQuery(ctx context.Context) *sql.Selector {
 // AuthRequestGroupBy is the group-by builder for AuthRequest entities.
 type AuthRequestGroupBy struct {
 	config
+	selector
 	fields []string
 	fns    []AggregateFunc
 	// intermediate query (i.e. traversal path).
@@ -458,209 +462,6 @@ func (argb *AuthRequestGroupBy) Scan(ctx context.Context, v interface{}) error {
 	return argb.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (argb *AuthRequestGroupBy) ScanX(ctx context.Context, v interface{}) {
-	if err := argb.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (argb *AuthRequestGroupBy) Strings(ctx context.Context) ([]string, error) {
-	if len(argb.fields) > 1 {
-		return nil, errors.New("db: AuthRequestGroupBy.Strings is not achievable when grouping more than 1 field")
-	}
-	var v []string
-	if err := argb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (argb *AuthRequestGroupBy) StringsX(ctx context.Context) []string {
-	v, err := argb.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (argb *AuthRequestGroupBy) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = argb.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authrequest.Label}
-	default:
-		err = fmt.Errorf("db: AuthRequestGroupBy.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (argb *AuthRequestGroupBy) StringX(ctx context.Context) string {
-	v, err := argb.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (argb *AuthRequestGroupBy) Ints(ctx context.Context) ([]int, error) {
-	if len(argb.fields) > 1 {
-		return nil, errors.New("db: AuthRequestGroupBy.Ints is not achievable when grouping more than 1 field")
-	}
-	var v []int
-	if err := argb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (argb *AuthRequestGroupBy) IntsX(ctx context.Context) []int {
-	v, err := argb.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (argb *AuthRequestGroupBy) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = argb.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authrequest.Label}
-	default:
-		err = fmt.Errorf("db: AuthRequestGroupBy.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (argb *AuthRequestGroupBy) IntX(ctx context.Context) int {
-	v, err := argb.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (argb *AuthRequestGroupBy) Float64s(ctx context.Context) ([]float64, error) {
-	if len(argb.fields) > 1 {
-		return nil, errors.New("db: AuthRequestGroupBy.Float64s is not achievable when grouping more than 1 field")
-	}
-	var v []float64
-	if err := argb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (argb *AuthRequestGroupBy) Float64sX(ctx context.Context) []float64 {
-	v, err := argb.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (argb *AuthRequestGroupBy) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = argb.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authrequest.Label}
-	default:
-		err = fmt.Errorf("db: AuthRequestGroupBy.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (argb *AuthRequestGroupBy) Float64X(ctx context.Context) float64 {
-	v, err := argb.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (argb *AuthRequestGroupBy) Bools(ctx context.Context) ([]bool, error) {
-	if len(argb.fields) > 1 {
-		return nil, errors.New("db: AuthRequestGroupBy.Bools is not achievable when grouping more than 1 field")
-	}
-	var v []bool
-	if err := argb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (argb *AuthRequestGroupBy) BoolsX(ctx context.Context) []bool {
-	v, err := argb.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (argb *AuthRequestGroupBy) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = argb.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authrequest.Label}
-	default:
-		err = fmt.Errorf("db: AuthRequestGroupBy.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (argb *AuthRequestGroupBy) BoolX(ctx context.Context) bool {
-	v, err := argb.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (argb *AuthRequestGroupBy) sqlScan(ctx context.Context, v interface{}) error {
 	for _, f := range argb.fields {
 		if !authrequest.ValidColumn(f) {
@@ -702,6 +503,7 @@ func (argb *AuthRequestGroupBy) sqlQuery() *sql.Selector {
 // AuthRequestSelect is the builder for selecting fields of AuthRequest entities.
 type AuthRequestSelect struct {
 	*AuthRequestQuery
+	selector
 	// intermediate query (i.e. traversal path).
 	sql *sql.Selector
 }
@@ -715,201 +517,6 @@ func (ars *AuthRequestSelect) Scan(ctx context.Context, v interface{}) error {
 	return ars.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (ars *AuthRequestSelect) ScanX(ctx context.Context, v interface{}) {
-	if err := ars.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from a selector. It is only allowed when selecting one field.
-func (ars *AuthRequestSelect) Strings(ctx context.Context) ([]string, error) {
-	if len(ars.fields) > 1 {
-		return nil, errors.New("db: AuthRequestSelect.Strings is not achievable when selecting more than 1 field")
-	}
-	var v []string
-	if err := ars.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (ars *AuthRequestSelect) StringsX(ctx context.Context) []string {
-	v, err := ars.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a selector. It is only allowed when selecting one field.
-func (ars *AuthRequestSelect) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = ars.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authrequest.Label}
-	default:
-		err = fmt.Errorf("db: AuthRequestSelect.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (ars *AuthRequestSelect) StringX(ctx context.Context) string {
-	v, err := ars.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from a selector. It is only allowed when selecting one field.
-func (ars *AuthRequestSelect) Ints(ctx context.Context) ([]int, error) {
-	if len(ars.fields) > 1 {
-		return nil, errors.New("db: AuthRequestSelect.Ints is not achievable when selecting more than 1 field")
-	}
-	var v []int
-	if err := ars.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (ars *AuthRequestSelect) IntsX(ctx context.Context) []int {
-	v, err := ars.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a selector. It is only allowed when selecting one field.
-func (ars *AuthRequestSelect) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = ars.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authrequest.Label}
-	default:
-		err = fmt.Errorf("db: AuthRequestSelect.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (ars *AuthRequestSelect) IntX(ctx context.Context) int {
-	v, err := ars.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
-func (ars *AuthRequestSelect) Float64s(ctx context.Context) ([]float64, error) {
-	if len(ars.fields) > 1 {
-		return nil, errors.New("db: AuthRequestSelect.Float64s is not achievable when selecting more than 1 field")
-	}
-	var v []float64
-	if err := ars.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (ars *AuthRequestSelect) Float64sX(ctx context.Context) []float64 {
-	v, err := ars.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
-func (ars *AuthRequestSelect) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = ars.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authrequest.Label}
-	default:
-		err = fmt.Errorf("db: AuthRequestSelect.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (ars *AuthRequestSelect) Float64X(ctx context.Context) float64 {
-	v, err := ars.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from a selector. It is only allowed when selecting one field.
-func (ars *AuthRequestSelect) Bools(ctx context.Context) ([]bool, error) {
-	if len(ars.fields) > 1 {
-		return nil, errors.New("db: AuthRequestSelect.Bools is not achievable when selecting more than 1 field")
-	}
-	var v []bool
-	if err := ars.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (ars *AuthRequestSelect) BoolsX(ctx context.Context) []bool {
-	v, err := ars.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a selector. It is only allowed when selecting one field.
-func (ars *AuthRequestSelect) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = ars.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{authrequest.Label}
-	default:
-		err = fmt.Errorf("db: AuthRequestSelect.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (ars *AuthRequestSelect) BoolX(ctx context.Context) bool {
-	v, err := ars.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (ars *AuthRequestSelect) sqlScan(ctx context.Context, v interface{}) error {
 	rows := &sql.Rows{}
 	query, args := ars.sql.Query()
diff --git a/storage/ent/db/authrequest_update.go b/storage/ent/db/authrequest_update.go
index 6e24a200..f0bf9b34 100644
--- a/storage/ent/db/authrequest_update.go
+++ b/storage/ent/db/authrequest_update.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -441,7 +441,7 @@ func (aru *AuthRequestUpdate) sqlSave(ctx context.Context) (n int, err error) {
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{authrequest.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return 0, err
 	}
@@ -661,9 +661,15 @@ func (aruo *AuthRequestUpdateOne) Save(ctx context.Context) (*AuthRequest, error
 			}
 			mut = aruo.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, aruo.mutation); err != nil {
+		v, err := mut.Mutate(ctx, aruo.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*AuthRequest)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from AuthRequestMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -896,7 +902,7 @@ func (aruo *AuthRequestUpdateOne) sqlSave(ctx context.Context) (_node *AuthReque
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{authrequest.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
diff --git a/storage/ent/db/client.go b/storage/ent/db/client.go
index 7a8e7ede..4bf55865 100644
--- a/storage/ent/db/client.go
+++ b/storage/ent/db/client.go
@@ -1,9 +1,10 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"log"
 
@@ -94,7 +95,7 @@ func Open(driverName, dataSourceName string, options ...Option) (*Client, error)
 // is used until the transaction is committed or rolled back.
 func (c *Client) Tx(ctx context.Context) (*Tx, error) {
 	if _, ok := c.driver.(*txDriver); ok {
-		return nil, fmt.Errorf("db: cannot start a transaction within a transaction")
+		return nil, errors.New("db: cannot start a transaction within a transaction")
 	}
 	tx, err := newTx(ctx, c.driver)
 	if err != nil {
@@ -121,7 +122,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) {
 // BeginTx returns a transactional client with specified options.
 func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
 	if _, ok := c.driver.(*txDriver); ok {
-		return nil, fmt.Errorf("ent: cannot start a transaction within a transaction")
+		return nil, errors.New("ent: cannot start a transaction within a transaction")
 	}
 	tx, err := c.driver.(interface {
 		BeginTx(context.Context, *sql.TxOptions) (dialect.Tx, error)
@@ -201,7 +202,7 @@ func (c *AuthCodeClient) Use(hooks ...Hook) {
 	c.hooks.AuthCode = append(c.hooks.AuthCode, hooks...)
 }
 
-// Create returns a create builder for AuthCode.
+// Create returns a builder for creating a AuthCode entity.
 func (c *AuthCodeClient) Create() *AuthCodeCreate {
 	mutation := newAuthCodeMutation(c.config, OpCreate)
 	return &AuthCodeCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
@@ -236,12 +237,12 @@ func (c *AuthCodeClient) Delete() *AuthCodeDelete {
 	return &AuthCodeDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
 }
 
-// DeleteOne returns a delete builder for the given entity.
+// DeleteOne returns a builder for deleting the given entity.
 func (c *AuthCodeClient) DeleteOne(ac *AuthCode) *AuthCodeDeleteOne {
 	return c.DeleteOneID(ac.ID)
 }
 
-// DeleteOneID returns a delete builder for the given id.
+// DeleteOne returns a builder for deleting the given entity by its id.
 func (c *AuthCodeClient) DeleteOneID(id string) *AuthCodeDeleteOne {
 	builder := c.Delete().Where(authcode.ID(id))
 	builder.mutation.id = &id
@@ -291,7 +292,7 @@ func (c *AuthRequestClient) Use(hooks ...Hook) {
 	c.hooks.AuthRequest = append(c.hooks.AuthRequest, hooks...)
 }
 
-// Create returns a create builder for AuthRequest.
+// Create returns a builder for creating a AuthRequest entity.
 func (c *AuthRequestClient) Create() *AuthRequestCreate {
 	mutation := newAuthRequestMutation(c.config, OpCreate)
 	return &AuthRequestCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
@@ -326,12 +327,12 @@ func (c *AuthRequestClient) Delete() *AuthRequestDelete {
 	return &AuthRequestDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
 }
 
-// DeleteOne returns a delete builder for the given entity.
+// DeleteOne returns a builder for deleting the given entity.
 func (c *AuthRequestClient) DeleteOne(ar *AuthRequest) *AuthRequestDeleteOne {
 	return c.DeleteOneID(ar.ID)
 }
 
-// DeleteOneID returns a delete builder for the given id.
+// DeleteOne returns a builder for deleting the given entity by its id.
 func (c *AuthRequestClient) DeleteOneID(id string) *AuthRequestDeleteOne {
 	builder := c.Delete().Where(authrequest.ID(id))
 	builder.mutation.id = &id
@@ -381,7 +382,7 @@ func (c *ConnectorClient) Use(hooks ...Hook) {
 	c.hooks.Connector = append(c.hooks.Connector, hooks...)
 }
 
-// Create returns a create builder for Connector.
+// Create returns a builder for creating a Connector entity.
 func (c *ConnectorClient) Create() *ConnectorCreate {
 	mutation := newConnectorMutation(c.config, OpCreate)
 	return &ConnectorCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
@@ -416,12 +417,12 @@ func (c *ConnectorClient) Delete() *ConnectorDelete {
 	return &ConnectorDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
 }
 
-// DeleteOne returns a delete builder for the given entity.
+// DeleteOne returns a builder for deleting the given entity.
 func (c *ConnectorClient) DeleteOne(co *Connector) *ConnectorDeleteOne {
 	return c.DeleteOneID(co.ID)
 }
 
-// DeleteOneID returns a delete builder for the given id.
+// DeleteOne returns a builder for deleting the given entity by its id.
 func (c *ConnectorClient) DeleteOneID(id string) *ConnectorDeleteOne {
 	builder := c.Delete().Where(connector.ID(id))
 	builder.mutation.id = &id
@@ -471,7 +472,7 @@ func (c *DeviceRequestClient) Use(hooks ...Hook) {
 	c.hooks.DeviceRequest = append(c.hooks.DeviceRequest, hooks...)
 }
 
-// Create returns a create builder for DeviceRequest.
+// Create returns a builder for creating a DeviceRequest entity.
 func (c *DeviceRequestClient) Create() *DeviceRequestCreate {
 	mutation := newDeviceRequestMutation(c.config, OpCreate)
 	return &DeviceRequestCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
@@ -506,12 +507,12 @@ func (c *DeviceRequestClient) Delete() *DeviceRequestDelete {
 	return &DeviceRequestDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
 }
 
-// DeleteOne returns a delete builder for the given entity.
+// DeleteOne returns a builder for deleting the given entity.
 func (c *DeviceRequestClient) DeleteOne(dr *DeviceRequest) *DeviceRequestDeleteOne {
 	return c.DeleteOneID(dr.ID)
 }
 
-// DeleteOneID returns a delete builder for the given id.
+// DeleteOne returns a builder for deleting the given entity by its id.
 func (c *DeviceRequestClient) DeleteOneID(id int) *DeviceRequestDeleteOne {
 	builder := c.Delete().Where(devicerequest.ID(id))
 	builder.mutation.id = &id
@@ -561,7 +562,7 @@ func (c *DeviceTokenClient) Use(hooks ...Hook) {
 	c.hooks.DeviceToken = append(c.hooks.DeviceToken, hooks...)
 }
 
-// Create returns a create builder for DeviceToken.
+// Create returns a builder for creating a DeviceToken entity.
 func (c *DeviceTokenClient) Create() *DeviceTokenCreate {
 	mutation := newDeviceTokenMutation(c.config, OpCreate)
 	return &DeviceTokenCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
@@ -596,12 +597,12 @@ func (c *DeviceTokenClient) Delete() *DeviceTokenDelete {
 	return &DeviceTokenDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
 }
 
-// DeleteOne returns a delete builder for the given entity.
+// DeleteOne returns a builder for deleting the given entity.
 func (c *DeviceTokenClient) DeleteOne(dt *DeviceToken) *DeviceTokenDeleteOne {
 	return c.DeleteOneID(dt.ID)
 }
 
-// DeleteOneID returns a delete builder for the given id.
+// DeleteOne returns a builder for deleting the given entity by its id.
 func (c *DeviceTokenClient) DeleteOneID(id int) *DeviceTokenDeleteOne {
 	builder := c.Delete().Where(devicetoken.ID(id))
 	builder.mutation.id = &id
@@ -651,7 +652,7 @@ func (c *KeysClient) Use(hooks ...Hook) {
 	c.hooks.Keys = append(c.hooks.Keys, hooks...)
 }
 
-// Create returns a create builder for Keys.
+// Create returns a builder for creating a Keys entity.
 func (c *KeysClient) Create() *KeysCreate {
 	mutation := newKeysMutation(c.config, OpCreate)
 	return &KeysCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
@@ -686,12 +687,12 @@ func (c *KeysClient) Delete() *KeysDelete {
 	return &KeysDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
 }
 
-// DeleteOne returns a delete builder for the given entity.
+// DeleteOne returns a builder for deleting the given entity.
 func (c *KeysClient) DeleteOne(k *Keys) *KeysDeleteOne {
 	return c.DeleteOneID(k.ID)
 }
 
-// DeleteOneID returns a delete builder for the given id.
+// DeleteOne returns a builder for deleting the given entity by its id.
 func (c *KeysClient) DeleteOneID(id string) *KeysDeleteOne {
 	builder := c.Delete().Where(keys.ID(id))
 	builder.mutation.id = &id
@@ -741,7 +742,7 @@ func (c *OAuth2ClientClient) Use(hooks ...Hook) {
 	c.hooks.OAuth2Client = append(c.hooks.OAuth2Client, hooks...)
 }
 
-// Create returns a create builder for OAuth2Client.
+// Create returns a builder for creating a OAuth2Client entity.
 func (c *OAuth2ClientClient) Create() *OAuth2ClientCreate {
 	mutation := newOAuth2ClientMutation(c.config, OpCreate)
 	return &OAuth2ClientCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
@@ -776,12 +777,12 @@ func (c *OAuth2ClientClient) Delete() *OAuth2ClientDelete {
 	return &OAuth2ClientDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
 }
 
-// DeleteOne returns a delete builder for the given entity.
+// DeleteOne returns a builder for deleting the given entity.
 func (c *OAuth2ClientClient) DeleteOne(o *OAuth2Client) *OAuth2ClientDeleteOne {
 	return c.DeleteOneID(o.ID)
 }
 
-// DeleteOneID returns a delete builder for the given id.
+// DeleteOne returns a builder for deleting the given entity by its id.
 func (c *OAuth2ClientClient) DeleteOneID(id string) *OAuth2ClientDeleteOne {
 	builder := c.Delete().Where(oauth2client.ID(id))
 	builder.mutation.id = &id
@@ -831,7 +832,7 @@ func (c *OfflineSessionClient) Use(hooks ...Hook) {
 	c.hooks.OfflineSession = append(c.hooks.OfflineSession, hooks...)
 }
 
-// Create returns a create builder for OfflineSession.
+// Create returns a builder for creating a OfflineSession entity.
 func (c *OfflineSessionClient) Create() *OfflineSessionCreate {
 	mutation := newOfflineSessionMutation(c.config, OpCreate)
 	return &OfflineSessionCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
@@ -866,12 +867,12 @@ func (c *OfflineSessionClient) Delete() *OfflineSessionDelete {
 	return &OfflineSessionDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
 }
 
-// DeleteOne returns a delete builder for the given entity.
+// DeleteOne returns a builder for deleting the given entity.
 func (c *OfflineSessionClient) DeleteOne(os *OfflineSession) *OfflineSessionDeleteOne {
 	return c.DeleteOneID(os.ID)
 }
 
-// DeleteOneID returns a delete builder for the given id.
+// DeleteOne returns a builder for deleting the given entity by its id.
 func (c *OfflineSessionClient) DeleteOneID(id string) *OfflineSessionDeleteOne {
 	builder := c.Delete().Where(offlinesession.ID(id))
 	builder.mutation.id = &id
@@ -921,7 +922,7 @@ func (c *PasswordClient) Use(hooks ...Hook) {
 	c.hooks.Password = append(c.hooks.Password, hooks...)
 }
 
-// Create returns a create builder for Password.
+// Create returns a builder for creating a Password entity.
 func (c *PasswordClient) Create() *PasswordCreate {
 	mutation := newPasswordMutation(c.config, OpCreate)
 	return &PasswordCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
@@ -956,12 +957,12 @@ func (c *PasswordClient) Delete() *PasswordDelete {
 	return &PasswordDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
 }
 
-// DeleteOne returns a delete builder for the given entity.
+// DeleteOne returns a builder for deleting the given entity.
 func (c *PasswordClient) DeleteOne(pa *Password) *PasswordDeleteOne {
 	return c.DeleteOneID(pa.ID)
 }
 
-// DeleteOneID returns a delete builder for the given id.
+// DeleteOne returns a builder for deleting the given entity by its id.
 func (c *PasswordClient) DeleteOneID(id int) *PasswordDeleteOne {
 	builder := c.Delete().Where(password.ID(id))
 	builder.mutation.id = &id
@@ -1011,7 +1012,7 @@ func (c *RefreshTokenClient) Use(hooks ...Hook) {
 	c.hooks.RefreshToken = append(c.hooks.RefreshToken, hooks...)
 }
 
-// Create returns a create builder for RefreshToken.
+// Create returns a builder for creating a RefreshToken entity.
 func (c *RefreshTokenClient) Create() *RefreshTokenCreate {
 	mutation := newRefreshTokenMutation(c.config, OpCreate)
 	return &RefreshTokenCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
@@ -1046,12 +1047,12 @@ func (c *RefreshTokenClient) Delete() *RefreshTokenDelete {
 	return &RefreshTokenDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
 }
 
-// DeleteOne returns a delete builder for the given entity.
+// DeleteOne returns a builder for deleting the given entity.
 func (c *RefreshTokenClient) DeleteOne(rt *RefreshToken) *RefreshTokenDeleteOne {
 	return c.DeleteOneID(rt.ID)
 }
 
-// DeleteOneID returns a delete builder for the given id.
+// DeleteOne returns a builder for deleting the given entity by its id.
 func (c *RefreshTokenClient) DeleteOneID(id string) *RefreshTokenDeleteOne {
 	builder := c.Delete().Where(refreshtoken.ID(id))
 	builder.mutation.id = &id
diff --git a/storage/ent/db/config.go b/storage/ent/db/config.go
index 6e1ffb6c..b26f166d 100644
--- a/storage/ent/db/config.go
+++ b/storage/ent/db/config.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
diff --git a/storage/ent/db/connector.go b/storage/ent/db/connector.go
index 3bcb7ee5..65cd4d25 100644
--- a/storage/ent/db/connector.go
+++ b/storage/ent/db/connector.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -94,11 +94,11 @@ func (c *Connector) Update() *ConnectorUpdateOne {
 // Unwrap unwraps the Connector entity that was returned from a transaction after it was closed,
 // so that all future queries will be executed through the driver which created the transaction.
 func (c *Connector) Unwrap() *Connector {
-	tx, ok := c.config.driver.(*txDriver)
+	_tx, ok := c.config.driver.(*txDriver)
 	if !ok {
 		panic("db: Connector is not a transactional entity")
 	}
-	c.config.driver = tx.drv
+	c.config.driver = _tx.drv
 	return c
 }
 
@@ -106,14 +106,17 @@ func (c *Connector) Unwrap() *Connector {
 func (c *Connector) String() string {
 	var builder strings.Builder
 	builder.WriteString("Connector(")
-	builder.WriteString(fmt.Sprintf("id=%v", c.ID))
-	builder.WriteString(", type=")
+	builder.WriteString(fmt.Sprintf("id=%v, ", c.ID))
+	builder.WriteString("type=")
 	builder.WriteString(c.Type)
-	builder.WriteString(", name=")
+	builder.WriteString(", ")
+	builder.WriteString("name=")
 	builder.WriteString(c.Name)
-	builder.WriteString(", resource_version=")
+	builder.WriteString(", ")
+	builder.WriteString("resource_version=")
 	builder.WriteString(c.ResourceVersion)
-	builder.WriteString(", config=")
+	builder.WriteString(", ")
+	builder.WriteString("config=")
 	builder.WriteString(fmt.Sprintf("%v", c.Config))
 	builder.WriteByte(')')
 	return builder.String()
diff --git a/storage/ent/db/connector/connector.go b/storage/ent/db/connector/connector.go
index 1ee43270..8f52a8f7 100644
--- a/storage/ent/db/connector/connector.go
+++ b/storage/ent/db/connector/connector.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package connector
 
diff --git a/storage/ent/db/connector/where.go b/storage/ent/db/connector/where.go
index 889a6dd7..e48576de 100644
--- a/storage/ent/db/connector/where.go
+++ b/storage/ent/db/connector/where.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package connector
 
@@ -31,12 +31,6 @@ func IDNEQ(id string) predicate.Connector {
 // IDIn applies the In predicate on the ID field.
 func IDIn(ids ...string) predicate.Connector {
 	return predicate.Connector(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -48,12 +42,6 @@ func IDIn(ids ...string) predicate.Connector {
 // IDNotIn applies the NotIn predicate on the ID field.
 func IDNotIn(ids ...string) predicate.Connector {
 	return predicate.Connector(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -139,12 +127,6 @@ func TypeIn(vs ...string) predicate.Connector {
 		v[i] = vs[i]
 	}
 	return predicate.Connector(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldType), v...))
 	})
 }
@@ -156,12 +138,6 @@ func TypeNotIn(vs ...string) predicate.Connector {
 		v[i] = vs[i]
 	}
 	return predicate.Connector(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldType), v...))
 	})
 }
@@ -250,12 +226,6 @@ func NameIn(vs ...string) predicate.Connector {
 		v[i] = vs[i]
 	}
 	return predicate.Connector(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldName), v...))
 	})
 }
@@ -267,12 +237,6 @@ func NameNotIn(vs ...string) predicate.Connector {
 		v[i] = vs[i]
 	}
 	return predicate.Connector(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldName), v...))
 	})
 }
@@ -361,12 +325,6 @@ func ResourceVersionIn(vs ...string) predicate.Connector {
 		v[i] = vs[i]
 	}
 	return predicate.Connector(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldResourceVersion), v...))
 	})
 }
@@ -378,12 +336,6 @@ func ResourceVersionNotIn(vs ...string) predicate.Connector {
 		v[i] = vs[i]
 	}
 	return predicate.Connector(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldResourceVersion), v...))
 	})
 }
@@ -472,12 +424,6 @@ func ConfigIn(vs ...[]byte) predicate.Connector {
 		v[i] = vs[i]
 	}
 	return predicate.Connector(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldConfig), v...))
 	})
 }
@@ -489,12 +435,6 @@ func ConfigNotIn(vs ...[]byte) predicate.Connector {
 		v[i] = vs[i]
 	}
 	return predicate.Connector(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldConfig), v...))
 	})
 }
diff --git a/storage/ent/db/connector_create.go b/storage/ent/db/connector_create.go
index b3836019..ecff1c2f 100644
--- a/storage/ent/db/connector_create.go
+++ b/storage/ent/db/connector_create.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -88,9 +88,15 @@ func (cc *ConnectorCreate) Save(ctx context.Context) (*Connector, error) {
 			}
 			mut = cc.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, cc.mutation); err != nil {
+		v, err := mut.Mutate(ctx, cc.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*Connector)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from ConnectorMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -153,7 +159,7 @@ func (cc *ConnectorCreate) sqlSave(ctx context.Context) (*Connector, error) {
 	_node, _spec := cc.createSpec()
 	if err := sqlgraph.CreateNode(ctx, cc.driver, _spec); err != nil {
 		if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
@@ -249,7 +255,7 @@ func (ccb *ConnectorCreateBulk) Save(ctx context.Context) ([]*Connector, error)
 					// Invoke the actual operation on the latest mutation in the chain.
 					if err = sqlgraph.BatchCreate(ctx, ccb.driver, spec); err != nil {
 						if sqlgraph.IsConstraintError(err) {
-							err = &ConstraintError{err.Error(), err}
+							err = &ConstraintError{msg: err.Error(), wrap: err}
 						}
 					}
 				}
diff --git a/storage/ent/db/connector_delete.go b/storage/ent/db/connector_delete.go
index 1cad771f..0c5381ee 100644
--- a/storage/ent/db/connector_delete.go
+++ b/storage/ent/db/connector_delete.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -84,7 +84,11 @@ func (cd *ConnectorDelete) sqlExec(ctx context.Context) (int, error) {
 			}
 		}
 	}
-	return sqlgraph.DeleteNodes(ctx, cd.driver, _spec)
+	affected, err := sqlgraph.DeleteNodes(ctx, cd.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	return affected, err
 }
 
 // ConnectorDeleteOne is the builder for deleting a single Connector entity.
diff --git a/storage/ent/db/connector_query.go b/storage/ent/db/connector_query.go
index f79b4047..32d60204 100644
--- a/storage/ent/db/connector_query.go
+++ b/storage/ent/db/connector_query.go
@@ -1,10 +1,9 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"math"
 
@@ -264,15 +263,17 @@ func (cq *ConnectorQuery) Clone() *ConnectorQuery {
 //		Scan(ctx, &v)
 //
 func (cq *ConnectorQuery) GroupBy(field string, fields ...string) *ConnectorGroupBy {
-	group := &ConnectorGroupBy{config: cq.config}
-	group.fields = append([]string{field}, fields...)
-	group.path = func(ctx context.Context) (prev *sql.Selector, err error) {
+	grbuild := &ConnectorGroupBy{config: cq.config}
+	grbuild.fields = append([]string{field}, fields...)
+	grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
 		if err := cq.prepareQuery(ctx); err != nil {
 			return nil, err
 		}
 		return cq.sqlQuery(ctx), nil
 	}
-	return group
+	grbuild.label = connector.Label
+	grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
+	return grbuild
 }
 
 // Select allows the selection one or more fields/columns for the given query,
@@ -290,7 +291,10 @@ func (cq *ConnectorQuery) GroupBy(field string, fields ...string) *ConnectorGrou
 //
 func (cq *ConnectorQuery) Select(fields ...string) *ConnectorSelect {
 	cq.fields = append(cq.fields, fields...)
-	return &ConnectorSelect{ConnectorQuery: cq}
+	selbuild := &ConnectorSelect{ConnectorQuery: cq}
+	selbuild.label = connector.Label
+	selbuild.flds, selbuild.scan = &cq.fields, selbuild.Scan
+	return selbuild
 }
 
 func (cq *ConnectorQuery) prepareQuery(ctx context.Context) error {
@@ -309,23 +313,22 @@ func (cq *ConnectorQuery) prepareQuery(ctx context.Context) error {
 	return nil
 }
 
-func (cq *ConnectorQuery) sqlAll(ctx context.Context) ([]*Connector, error) {
+func (cq *ConnectorQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Connector, error) {
 	var (
 		nodes = []*Connector{}
 		_spec = cq.querySpec()
 	)
 	_spec.ScanValues = func(columns []string) ([]interface{}, error) {
-		node := &Connector{config: cq.config}
-		nodes = append(nodes, node)
-		return node.scanValues(columns)
+		return (*Connector).scanValues(nil, columns)
 	}
 	_spec.Assign = func(columns []string, values []interface{}) error {
-		if len(nodes) == 0 {
-			return fmt.Errorf("db: Assign called without calling ScanValues")
-		}
-		node := nodes[len(nodes)-1]
+		node := &Connector{config: cq.config}
+		nodes = append(nodes, node)
 		return node.assignValues(columns, values)
 	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
 	if err := sqlgraph.QueryNodes(ctx, cq.driver, _spec); err != nil {
 		return nil, err
 	}
@@ -435,6 +438,7 @@ func (cq *ConnectorQuery) sqlQuery(ctx context.Context) *sql.Selector {
 // ConnectorGroupBy is the group-by builder for Connector entities.
 type ConnectorGroupBy struct {
 	config
+	selector
 	fields []string
 	fns    []AggregateFunc
 	// intermediate query (i.e. traversal path).
@@ -458,209 +462,6 @@ func (cgb *ConnectorGroupBy) Scan(ctx context.Context, v interface{}) error {
 	return cgb.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (cgb *ConnectorGroupBy) ScanX(ctx context.Context, v interface{}) {
-	if err := cgb.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (cgb *ConnectorGroupBy) Strings(ctx context.Context) ([]string, error) {
-	if len(cgb.fields) > 1 {
-		return nil, errors.New("db: ConnectorGroupBy.Strings is not achievable when grouping more than 1 field")
-	}
-	var v []string
-	if err := cgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (cgb *ConnectorGroupBy) StringsX(ctx context.Context) []string {
-	v, err := cgb.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (cgb *ConnectorGroupBy) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = cgb.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{connector.Label}
-	default:
-		err = fmt.Errorf("db: ConnectorGroupBy.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (cgb *ConnectorGroupBy) StringX(ctx context.Context) string {
-	v, err := cgb.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (cgb *ConnectorGroupBy) Ints(ctx context.Context) ([]int, error) {
-	if len(cgb.fields) > 1 {
-		return nil, errors.New("db: ConnectorGroupBy.Ints is not achievable when grouping more than 1 field")
-	}
-	var v []int
-	if err := cgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (cgb *ConnectorGroupBy) IntsX(ctx context.Context) []int {
-	v, err := cgb.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (cgb *ConnectorGroupBy) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = cgb.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{connector.Label}
-	default:
-		err = fmt.Errorf("db: ConnectorGroupBy.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (cgb *ConnectorGroupBy) IntX(ctx context.Context) int {
-	v, err := cgb.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (cgb *ConnectorGroupBy) Float64s(ctx context.Context) ([]float64, error) {
-	if len(cgb.fields) > 1 {
-		return nil, errors.New("db: ConnectorGroupBy.Float64s is not achievable when grouping more than 1 field")
-	}
-	var v []float64
-	if err := cgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (cgb *ConnectorGroupBy) Float64sX(ctx context.Context) []float64 {
-	v, err := cgb.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (cgb *ConnectorGroupBy) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = cgb.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{connector.Label}
-	default:
-		err = fmt.Errorf("db: ConnectorGroupBy.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (cgb *ConnectorGroupBy) Float64X(ctx context.Context) float64 {
-	v, err := cgb.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (cgb *ConnectorGroupBy) Bools(ctx context.Context) ([]bool, error) {
-	if len(cgb.fields) > 1 {
-		return nil, errors.New("db: ConnectorGroupBy.Bools is not achievable when grouping more than 1 field")
-	}
-	var v []bool
-	if err := cgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (cgb *ConnectorGroupBy) BoolsX(ctx context.Context) []bool {
-	v, err := cgb.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (cgb *ConnectorGroupBy) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = cgb.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{connector.Label}
-	default:
-		err = fmt.Errorf("db: ConnectorGroupBy.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (cgb *ConnectorGroupBy) BoolX(ctx context.Context) bool {
-	v, err := cgb.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (cgb *ConnectorGroupBy) sqlScan(ctx context.Context, v interface{}) error {
 	for _, f := range cgb.fields {
 		if !connector.ValidColumn(f) {
@@ -702,6 +503,7 @@ func (cgb *ConnectorGroupBy) sqlQuery() *sql.Selector {
 // ConnectorSelect is the builder for selecting fields of Connector entities.
 type ConnectorSelect struct {
 	*ConnectorQuery
+	selector
 	// intermediate query (i.e. traversal path).
 	sql *sql.Selector
 }
@@ -715,201 +517,6 @@ func (cs *ConnectorSelect) Scan(ctx context.Context, v interface{}) error {
 	return cs.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (cs *ConnectorSelect) ScanX(ctx context.Context, v interface{}) {
-	if err := cs.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from a selector. It is only allowed when selecting one field.
-func (cs *ConnectorSelect) Strings(ctx context.Context) ([]string, error) {
-	if len(cs.fields) > 1 {
-		return nil, errors.New("db: ConnectorSelect.Strings is not achievable when selecting more than 1 field")
-	}
-	var v []string
-	if err := cs.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (cs *ConnectorSelect) StringsX(ctx context.Context) []string {
-	v, err := cs.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a selector. It is only allowed when selecting one field.
-func (cs *ConnectorSelect) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = cs.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{connector.Label}
-	default:
-		err = fmt.Errorf("db: ConnectorSelect.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (cs *ConnectorSelect) StringX(ctx context.Context) string {
-	v, err := cs.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from a selector. It is only allowed when selecting one field.
-func (cs *ConnectorSelect) Ints(ctx context.Context) ([]int, error) {
-	if len(cs.fields) > 1 {
-		return nil, errors.New("db: ConnectorSelect.Ints is not achievable when selecting more than 1 field")
-	}
-	var v []int
-	if err := cs.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (cs *ConnectorSelect) IntsX(ctx context.Context) []int {
-	v, err := cs.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a selector. It is only allowed when selecting one field.
-func (cs *ConnectorSelect) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = cs.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{connector.Label}
-	default:
-		err = fmt.Errorf("db: ConnectorSelect.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (cs *ConnectorSelect) IntX(ctx context.Context) int {
-	v, err := cs.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
-func (cs *ConnectorSelect) Float64s(ctx context.Context) ([]float64, error) {
-	if len(cs.fields) > 1 {
-		return nil, errors.New("db: ConnectorSelect.Float64s is not achievable when selecting more than 1 field")
-	}
-	var v []float64
-	if err := cs.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (cs *ConnectorSelect) Float64sX(ctx context.Context) []float64 {
-	v, err := cs.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
-func (cs *ConnectorSelect) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = cs.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{connector.Label}
-	default:
-		err = fmt.Errorf("db: ConnectorSelect.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (cs *ConnectorSelect) Float64X(ctx context.Context) float64 {
-	v, err := cs.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from a selector. It is only allowed when selecting one field.
-func (cs *ConnectorSelect) Bools(ctx context.Context) ([]bool, error) {
-	if len(cs.fields) > 1 {
-		return nil, errors.New("db: ConnectorSelect.Bools is not achievable when selecting more than 1 field")
-	}
-	var v []bool
-	if err := cs.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (cs *ConnectorSelect) BoolsX(ctx context.Context) []bool {
-	v, err := cs.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a selector. It is only allowed when selecting one field.
-func (cs *ConnectorSelect) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = cs.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{connector.Label}
-	default:
-		err = fmt.Errorf("db: ConnectorSelect.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (cs *ConnectorSelect) BoolX(ctx context.Context) bool {
-	v, err := cs.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (cs *ConnectorSelect) sqlScan(ctx context.Context, v interface{}) error {
 	rows := &sql.Rows{}
 	query, args := cs.sql.Query()
diff --git a/storage/ent/db/connector_update.go b/storage/ent/db/connector_update.go
index b11c1aa5..736d0a62 100644
--- a/storage/ent/db/connector_update.go
+++ b/storage/ent/db/connector_update.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -181,7 +181,7 @@ func (cu *ConnectorUpdate) sqlSave(ctx context.Context) (n int, err error) {
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{connector.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return 0, err
 	}
@@ -263,9 +263,15 @@ func (cuo *ConnectorUpdateOne) Save(ctx context.Context) (*Connector, error) {
 			}
 			mut = cuo.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, cuo.mutation); err != nil {
+		v, err := mut.Mutate(ctx, cuo.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*Connector)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from ConnectorMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -377,7 +383,7 @@ func (cuo *ConnectorUpdateOne) sqlSave(ctx context.Context) (_node *Connector, e
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{connector.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
diff --git a/storage/ent/db/context.go b/storage/ent/db/context.go
index 544570db..95e1ad8b 100644
--- a/storage/ent/db/context.go
+++ b/storage/ent/db/context.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
diff --git a/storage/ent/db/devicerequest.go b/storage/ent/db/devicerequest.go
index 24da4a46..d358f174 100644
--- a/storage/ent/db/devicerequest.go
+++ b/storage/ent/db/devicerequest.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -118,11 +118,11 @@ func (dr *DeviceRequest) Update() *DeviceRequestUpdateOne {
 // Unwrap unwraps the DeviceRequest entity that was returned from a transaction after it was closed,
 // so that all future queries will be executed through the driver which created the transaction.
 func (dr *DeviceRequest) Unwrap() *DeviceRequest {
-	tx, ok := dr.config.driver.(*txDriver)
+	_tx, ok := dr.config.driver.(*txDriver)
 	if !ok {
 		panic("db: DeviceRequest is not a transactional entity")
 	}
-	dr.config.driver = tx.drv
+	dr.config.driver = _tx.drv
 	return dr
 }
 
@@ -130,18 +130,23 @@ func (dr *DeviceRequest) Unwrap() *DeviceRequest {
 func (dr *DeviceRequest) String() string {
 	var builder strings.Builder
 	builder.WriteString("DeviceRequest(")
-	builder.WriteString(fmt.Sprintf("id=%v", dr.ID))
-	builder.WriteString(", user_code=")
+	builder.WriteString(fmt.Sprintf("id=%v, ", dr.ID))
+	builder.WriteString("user_code=")
 	builder.WriteString(dr.UserCode)
-	builder.WriteString(", device_code=")
+	builder.WriteString(", ")
+	builder.WriteString("device_code=")
 	builder.WriteString(dr.DeviceCode)
-	builder.WriteString(", client_id=")
+	builder.WriteString(", ")
+	builder.WriteString("client_id=")
 	builder.WriteString(dr.ClientID)
-	builder.WriteString(", client_secret=")
+	builder.WriteString(", ")
+	builder.WriteString("client_secret=")
 	builder.WriteString(dr.ClientSecret)
-	builder.WriteString(", scopes=")
+	builder.WriteString(", ")
+	builder.WriteString("scopes=")
 	builder.WriteString(fmt.Sprintf("%v", dr.Scopes))
-	builder.WriteString(", expiry=")
+	builder.WriteString(", ")
+	builder.WriteString("expiry=")
 	builder.WriteString(dr.Expiry.Format(time.ANSIC))
 	builder.WriteByte(')')
 	return builder.String()
diff --git a/storage/ent/db/devicerequest/devicerequest.go b/storage/ent/db/devicerequest/devicerequest.go
index 487662ce..5dd032d6 100644
--- a/storage/ent/db/devicerequest/devicerequest.go
+++ b/storage/ent/db/devicerequest/devicerequest.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package devicerequest
 
diff --git a/storage/ent/db/devicerequest/where.go b/storage/ent/db/devicerequest/where.go
index a9273bbd..5cb5ce44 100644
--- a/storage/ent/db/devicerequest/where.go
+++ b/storage/ent/db/devicerequest/where.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package devicerequest
 
@@ -33,12 +33,6 @@ func IDNEQ(id int) predicate.DeviceRequest {
 // IDIn applies the In predicate on the ID field.
 func IDIn(ids ...int) predicate.DeviceRequest {
 	return predicate.DeviceRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -50,12 +44,6 @@ func IDIn(ids ...int) predicate.DeviceRequest {
 // IDNotIn applies the NotIn predicate on the ID field.
 func IDNotIn(ids ...int) predicate.DeviceRequest {
 	return predicate.DeviceRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -148,12 +136,6 @@ func UserCodeIn(vs ...string) predicate.DeviceRequest {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldUserCode), v...))
 	})
 }
@@ -165,12 +147,6 @@ func UserCodeNotIn(vs ...string) predicate.DeviceRequest {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldUserCode), v...))
 	})
 }
@@ -259,12 +235,6 @@ func DeviceCodeIn(vs ...string) predicate.DeviceRequest {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldDeviceCode), v...))
 	})
 }
@@ -276,12 +246,6 @@ func DeviceCodeNotIn(vs ...string) predicate.DeviceRequest {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldDeviceCode), v...))
 	})
 }
@@ -370,12 +334,6 @@ func ClientIDIn(vs ...string) predicate.DeviceRequest {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClientID), v...))
 	})
 }
@@ -387,12 +345,6 @@ func ClientIDNotIn(vs ...string) predicate.DeviceRequest {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClientID), v...))
 	})
 }
@@ -481,12 +433,6 @@ func ClientSecretIn(vs ...string) predicate.DeviceRequest {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClientSecret), v...))
 	})
 }
@@ -498,12 +444,6 @@ func ClientSecretNotIn(vs ...string) predicate.DeviceRequest {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClientSecret), v...))
 	})
 }
@@ -606,12 +546,6 @@ func ExpiryIn(vs ...time.Time) predicate.DeviceRequest {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldExpiry), v...))
 	})
 }
@@ -623,12 +557,6 @@ func ExpiryNotIn(vs ...time.Time) predicate.DeviceRequest {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceRequest(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldExpiry), v...))
 	})
 }
diff --git a/storage/ent/db/devicerequest_create.go b/storage/ent/db/devicerequest_create.go
index 7600b47b..ae7644ca 100644
--- a/storage/ent/db/devicerequest_create.go
+++ b/storage/ent/db/devicerequest_create.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -95,9 +95,15 @@ func (drc *DeviceRequestCreate) Save(ctx context.Context) (*DeviceRequest, error
 			}
 			mut = drc.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, drc.mutation); err != nil {
+		v, err := mut.Mutate(ctx, drc.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*DeviceRequest)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from DeviceRequestMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -168,7 +174,7 @@ func (drc *DeviceRequestCreate) sqlSave(ctx context.Context) (*DeviceRequest, er
 	_node, _spec := drc.createSpec()
 	if err := sqlgraph.CreateNode(ctx, drc.driver, _spec); err != nil {
 		if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
@@ -271,7 +277,7 @@ func (drcb *DeviceRequestCreateBulk) Save(ctx context.Context) ([]*DeviceRequest
 					// Invoke the actual operation on the latest mutation in the chain.
 					if err = sqlgraph.BatchCreate(ctx, drcb.driver, spec); err != nil {
 						if sqlgraph.IsConstraintError(err) {
-							err = &ConstraintError{err.Error(), err}
+							err = &ConstraintError{msg: err.Error(), wrap: err}
 						}
 					}
 				}
@@ -279,11 +285,11 @@ func (drcb *DeviceRequestCreateBulk) Save(ctx context.Context) ([]*DeviceRequest
 					return nil, err
 				}
 				mutation.id = &nodes[i].ID
-				mutation.done = true
 				if specs[i].ID.Value != nil {
 					id := specs[i].ID.Value.(int64)
 					nodes[i].ID = int(id)
 				}
+				mutation.done = true
 				return nodes[i], nil
 			})
 			for i := len(builder.hooks) - 1; i >= 0; i-- {
diff --git a/storage/ent/db/devicerequest_delete.go b/storage/ent/db/devicerequest_delete.go
index 1a642622..635a8a49 100644
--- a/storage/ent/db/devicerequest_delete.go
+++ b/storage/ent/db/devicerequest_delete.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -84,7 +84,11 @@ func (drd *DeviceRequestDelete) sqlExec(ctx context.Context) (int, error) {
 			}
 		}
 	}
-	return sqlgraph.DeleteNodes(ctx, drd.driver, _spec)
+	affected, err := sqlgraph.DeleteNodes(ctx, drd.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	return affected, err
 }
 
 // DeviceRequestDeleteOne is the builder for deleting a single DeviceRequest entity.
diff --git a/storage/ent/db/devicerequest_query.go b/storage/ent/db/devicerequest_query.go
index f6839821..3fd43dd8 100644
--- a/storage/ent/db/devicerequest_query.go
+++ b/storage/ent/db/devicerequest_query.go
@@ -1,10 +1,9 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"math"
 
@@ -264,15 +263,17 @@ func (drq *DeviceRequestQuery) Clone() *DeviceRequestQuery {
 //		Scan(ctx, &v)
 //
 func (drq *DeviceRequestQuery) GroupBy(field string, fields ...string) *DeviceRequestGroupBy {
-	group := &DeviceRequestGroupBy{config: drq.config}
-	group.fields = append([]string{field}, fields...)
-	group.path = func(ctx context.Context) (prev *sql.Selector, err error) {
+	grbuild := &DeviceRequestGroupBy{config: drq.config}
+	grbuild.fields = append([]string{field}, fields...)
+	grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
 		if err := drq.prepareQuery(ctx); err != nil {
 			return nil, err
 		}
 		return drq.sqlQuery(ctx), nil
 	}
-	return group
+	grbuild.label = devicerequest.Label
+	grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
+	return grbuild
 }
 
 // Select allows the selection one or more fields/columns for the given query,
@@ -290,7 +291,10 @@ func (drq *DeviceRequestQuery) GroupBy(field string, fields ...string) *DeviceRe
 //
 func (drq *DeviceRequestQuery) Select(fields ...string) *DeviceRequestSelect {
 	drq.fields = append(drq.fields, fields...)
-	return &DeviceRequestSelect{DeviceRequestQuery: drq}
+	selbuild := &DeviceRequestSelect{DeviceRequestQuery: drq}
+	selbuild.label = devicerequest.Label
+	selbuild.flds, selbuild.scan = &drq.fields, selbuild.Scan
+	return selbuild
 }
 
 func (drq *DeviceRequestQuery) prepareQuery(ctx context.Context) error {
@@ -309,23 +313,22 @@ func (drq *DeviceRequestQuery) prepareQuery(ctx context.Context) error {
 	return nil
 }
 
-func (drq *DeviceRequestQuery) sqlAll(ctx context.Context) ([]*DeviceRequest, error) {
+func (drq *DeviceRequestQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*DeviceRequest, error) {
 	var (
 		nodes = []*DeviceRequest{}
 		_spec = drq.querySpec()
 	)
 	_spec.ScanValues = func(columns []string) ([]interface{}, error) {
-		node := &DeviceRequest{config: drq.config}
-		nodes = append(nodes, node)
-		return node.scanValues(columns)
+		return (*DeviceRequest).scanValues(nil, columns)
 	}
 	_spec.Assign = func(columns []string, values []interface{}) error {
-		if len(nodes) == 0 {
-			return fmt.Errorf("db: Assign called without calling ScanValues")
-		}
-		node := nodes[len(nodes)-1]
+		node := &DeviceRequest{config: drq.config}
+		nodes = append(nodes, node)
 		return node.assignValues(columns, values)
 	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
 	if err := sqlgraph.QueryNodes(ctx, drq.driver, _spec); err != nil {
 		return nil, err
 	}
@@ -435,6 +438,7 @@ func (drq *DeviceRequestQuery) sqlQuery(ctx context.Context) *sql.Selector {
 // DeviceRequestGroupBy is the group-by builder for DeviceRequest entities.
 type DeviceRequestGroupBy struct {
 	config
+	selector
 	fields []string
 	fns    []AggregateFunc
 	// intermediate query (i.e. traversal path).
@@ -458,209 +462,6 @@ func (drgb *DeviceRequestGroupBy) Scan(ctx context.Context, v interface{}) error
 	return drgb.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (drgb *DeviceRequestGroupBy) ScanX(ctx context.Context, v interface{}) {
-	if err := drgb.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (drgb *DeviceRequestGroupBy) Strings(ctx context.Context) ([]string, error) {
-	if len(drgb.fields) > 1 {
-		return nil, errors.New("db: DeviceRequestGroupBy.Strings is not achievable when grouping more than 1 field")
-	}
-	var v []string
-	if err := drgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (drgb *DeviceRequestGroupBy) StringsX(ctx context.Context) []string {
-	v, err := drgb.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (drgb *DeviceRequestGroupBy) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = drgb.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicerequest.Label}
-	default:
-		err = fmt.Errorf("db: DeviceRequestGroupBy.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (drgb *DeviceRequestGroupBy) StringX(ctx context.Context) string {
-	v, err := drgb.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (drgb *DeviceRequestGroupBy) Ints(ctx context.Context) ([]int, error) {
-	if len(drgb.fields) > 1 {
-		return nil, errors.New("db: DeviceRequestGroupBy.Ints is not achievable when grouping more than 1 field")
-	}
-	var v []int
-	if err := drgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (drgb *DeviceRequestGroupBy) IntsX(ctx context.Context) []int {
-	v, err := drgb.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (drgb *DeviceRequestGroupBy) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = drgb.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicerequest.Label}
-	default:
-		err = fmt.Errorf("db: DeviceRequestGroupBy.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (drgb *DeviceRequestGroupBy) IntX(ctx context.Context) int {
-	v, err := drgb.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (drgb *DeviceRequestGroupBy) Float64s(ctx context.Context) ([]float64, error) {
-	if len(drgb.fields) > 1 {
-		return nil, errors.New("db: DeviceRequestGroupBy.Float64s is not achievable when grouping more than 1 field")
-	}
-	var v []float64
-	if err := drgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (drgb *DeviceRequestGroupBy) Float64sX(ctx context.Context) []float64 {
-	v, err := drgb.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (drgb *DeviceRequestGroupBy) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = drgb.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicerequest.Label}
-	default:
-		err = fmt.Errorf("db: DeviceRequestGroupBy.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (drgb *DeviceRequestGroupBy) Float64X(ctx context.Context) float64 {
-	v, err := drgb.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (drgb *DeviceRequestGroupBy) Bools(ctx context.Context) ([]bool, error) {
-	if len(drgb.fields) > 1 {
-		return nil, errors.New("db: DeviceRequestGroupBy.Bools is not achievable when grouping more than 1 field")
-	}
-	var v []bool
-	if err := drgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (drgb *DeviceRequestGroupBy) BoolsX(ctx context.Context) []bool {
-	v, err := drgb.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (drgb *DeviceRequestGroupBy) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = drgb.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicerequest.Label}
-	default:
-		err = fmt.Errorf("db: DeviceRequestGroupBy.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (drgb *DeviceRequestGroupBy) BoolX(ctx context.Context) bool {
-	v, err := drgb.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (drgb *DeviceRequestGroupBy) sqlScan(ctx context.Context, v interface{}) error {
 	for _, f := range drgb.fields {
 		if !devicerequest.ValidColumn(f) {
@@ -702,6 +503,7 @@ func (drgb *DeviceRequestGroupBy) sqlQuery() *sql.Selector {
 // DeviceRequestSelect is the builder for selecting fields of DeviceRequest entities.
 type DeviceRequestSelect struct {
 	*DeviceRequestQuery
+	selector
 	// intermediate query (i.e. traversal path).
 	sql *sql.Selector
 }
@@ -715,201 +517,6 @@ func (drs *DeviceRequestSelect) Scan(ctx context.Context, v interface{}) error {
 	return drs.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (drs *DeviceRequestSelect) ScanX(ctx context.Context, v interface{}) {
-	if err := drs.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from a selector. It is only allowed when selecting one field.
-func (drs *DeviceRequestSelect) Strings(ctx context.Context) ([]string, error) {
-	if len(drs.fields) > 1 {
-		return nil, errors.New("db: DeviceRequestSelect.Strings is not achievable when selecting more than 1 field")
-	}
-	var v []string
-	if err := drs.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (drs *DeviceRequestSelect) StringsX(ctx context.Context) []string {
-	v, err := drs.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a selector. It is only allowed when selecting one field.
-func (drs *DeviceRequestSelect) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = drs.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicerequest.Label}
-	default:
-		err = fmt.Errorf("db: DeviceRequestSelect.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (drs *DeviceRequestSelect) StringX(ctx context.Context) string {
-	v, err := drs.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from a selector. It is only allowed when selecting one field.
-func (drs *DeviceRequestSelect) Ints(ctx context.Context) ([]int, error) {
-	if len(drs.fields) > 1 {
-		return nil, errors.New("db: DeviceRequestSelect.Ints is not achievable when selecting more than 1 field")
-	}
-	var v []int
-	if err := drs.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (drs *DeviceRequestSelect) IntsX(ctx context.Context) []int {
-	v, err := drs.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a selector. It is only allowed when selecting one field.
-func (drs *DeviceRequestSelect) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = drs.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicerequest.Label}
-	default:
-		err = fmt.Errorf("db: DeviceRequestSelect.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (drs *DeviceRequestSelect) IntX(ctx context.Context) int {
-	v, err := drs.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
-func (drs *DeviceRequestSelect) Float64s(ctx context.Context) ([]float64, error) {
-	if len(drs.fields) > 1 {
-		return nil, errors.New("db: DeviceRequestSelect.Float64s is not achievable when selecting more than 1 field")
-	}
-	var v []float64
-	if err := drs.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (drs *DeviceRequestSelect) Float64sX(ctx context.Context) []float64 {
-	v, err := drs.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
-func (drs *DeviceRequestSelect) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = drs.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicerequest.Label}
-	default:
-		err = fmt.Errorf("db: DeviceRequestSelect.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (drs *DeviceRequestSelect) Float64X(ctx context.Context) float64 {
-	v, err := drs.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from a selector. It is only allowed when selecting one field.
-func (drs *DeviceRequestSelect) Bools(ctx context.Context) ([]bool, error) {
-	if len(drs.fields) > 1 {
-		return nil, errors.New("db: DeviceRequestSelect.Bools is not achievable when selecting more than 1 field")
-	}
-	var v []bool
-	if err := drs.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (drs *DeviceRequestSelect) BoolsX(ctx context.Context) []bool {
-	v, err := drs.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a selector. It is only allowed when selecting one field.
-func (drs *DeviceRequestSelect) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = drs.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicerequest.Label}
-	default:
-		err = fmt.Errorf("db: DeviceRequestSelect.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (drs *DeviceRequestSelect) BoolX(ctx context.Context) bool {
-	v, err := drs.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (drs *DeviceRequestSelect) sqlScan(ctx context.Context, v interface{}) error {
 	rows := &sql.Rows{}
 	query, args := drs.sql.Query()
diff --git a/storage/ent/db/devicerequest_update.go b/storage/ent/db/devicerequest_update.go
index e47e565a..2bf38af6 100644
--- a/storage/ent/db/devicerequest_update.go
+++ b/storage/ent/db/devicerequest_update.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -230,7 +230,7 @@ func (dru *DeviceRequestUpdate) sqlSave(ctx context.Context) (n int, err error)
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{devicerequest.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return 0, err
 	}
@@ -330,9 +330,15 @@ func (druo *DeviceRequestUpdateOne) Save(ctx context.Context) (*DeviceRequest, e
 			}
 			mut = druo.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, druo.mutation); err != nil {
+		v, err := mut.Mutate(ctx, druo.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*DeviceRequest)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from DeviceRequestMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -474,7 +480,7 @@ func (druo *DeviceRequestUpdateOne) sqlSave(ctx context.Context) (_node *DeviceR
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{devicerequest.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
diff --git a/storage/ent/db/devicetoken.go b/storage/ent/db/devicetoken.go
index 1731d1f0..0daa1280 100644
--- a/storage/ent/db/devicetoken.go
+++ b/storage/ent/db/devicetoken.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -28,6 +28,10 @@ type DeviceToken struct {
 	LastRequest time.Time `json:"last_request,omitempty"`
 	// PollInterval holds the value of the "poll_interval" field.
 	PollInterval int `json:"poll_interval,omitempty"`
+	// CodeChallenge holds the value of the "code_challenge" field.
+	CodeChallenge string `json:"code_challenge,omitempty"`
+	// CodeChallengeMethod holds the value of the "code_challenge_method" field.
+	CodeChallengeMethod string `json:"code_challenge_method,omitempty"`
 }
 
 // scanValues returns the types for scanning values from sql.Rows.
@@ -39,7 +43,7 @@ func (*DeviceToken) scanValues(columns []string) ([]interface{}, error) {
 			values[i] = new([]byte)
 		case devicetoken.FieldID, devicetoken.FieldPollInterval:
 			values[i] = new(sql.NullInt64)
-		case devicetoken.FieldDeviceCode, devicetoken.FieldStatus:
+		case devicetoken.FieldDeviceCode, devicetoken.FieldStatus, devicetoken.FieldCodeChallenge, devicetoken.FieldCodeChallengeMethod:
 			values[i] = new(sql.NullString)
 		case devicetoken.FieldExpiry, devicetoken.FieldLastRequest:
 			values[i] = new(sql.NullTime)
@@ -100,6 +104,18 @@ func (dt *DeviceToken) assignValues(columns []string, values []interface{}) erro
 			} else if value.Valid {
 				dt.PollInterval = int(value.Int64)
 			}
+		case devicetoken.FieldCodeChallenge:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field code_challenge", values[i])
+			} else if value.Valid {
+				dt.CodeChallenge = value.String
+			}
+		case devicetoken.FieldCodeChallengeMethod:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field code_challenge_method", values[i])
+			} else if value.Valid {
+				dt.CodeChallengeMethod = value.String
+			}
 		}
 	}
 	return nil
@@ -115,11 +131,11 @@ func (dt *DeviceToken) Update() *DeviceTokenUpdateOne {
 // Unwrap unwraps the DeviceToken entity that was returned from a transaction after it was closed,
 // so that all future queries will be executed through the driver which created the transaction.
 func (dt *DeviceToken) Unwrap() *DeviceToken {
-	tx, ok := dt.config.driver.(*txDriver)
+	_tx, ok := dt.config.driver.(*txDriver)
 	if !ok {
 		panic("db: DeviceToken is not a transactional entity")
 	}
-	dt.config.driver = tx.drv
+	dt.config.driver = _tx.drv
 	return dt
 }
 
@@ -127,21 +143,32 @@ func (dt *DeviceToken) Unwrap() *DeviceToken {
 func (dt *DeviceToken) String() string {
 	var builder strings.Builder
 	builder.WriteString("DeviceToken(")
-	builder.WriteString(fmt.Sprintf("id=%v", dt.ID))
-	builder.WriteString(", device_code=")
+	builder.WriteString(fmt.Sprintf("id=%v, ", dt.ID))
+	builder.WriteString("device_code=")
 	builder.WriteString(dt.DeviceCode)
-	builder.WriteString(", status=")
+	builder.WriteString(", ")
+	builder.WriteString("status=")
 	builder.WriteString(dt.Status)
+	builder.WriteString(", ")
 	if v := dt.Token; v != nil {
-		builder.WriteString(", token=")
+		builder.WriteString("token=")
 		builder.WriteString(fmt.Sprintf("%v", *v))
 	}
-	builder.WriteString(", expiry=")
+	builder.WriteString(", ")
+	builder.WriteString("expiry=")
 	builder.WriteString(dt.Expiry.Format(time.ANSIC))
-	builder.WriteString(", last_request=")
+	builder.WriteString(", ")
+	builder.WriteString("last_request=")
 	builder.WriteString(dt.LastRequest.Format(time.ANSIC))
-	builder.WriteString(", poll_interval=")
+	builder.WriteString(", ")
+	builder.WriteString("poll_interval=")
 	builder.WriteString(fmt.Sprintf("%v", dt.PollInterval))
+	builder.WriteString(", ")
+	builder.WriteString("code_challenge=")
+	builder.WriteString(dt.CodeChallenge)
+	builder.WriteString(", ")
+	builder.WriteString("code_challenge_method=")
+	builder.WriteString(dt.CodeChallengeMethod)
 	builder.WriteByte(')')
 	return builder.String()
 }
diff --git a/storage/ent/db/devicetoken/devicetoken.go b/storage/ent/db/devicetoken/devicetoken.go
index 7af65799..f40b1b04 100644
--- a/storage/ent/db/devicetoken/devicetoken.go
+++ b/storage/ent/db/devicetoken/devicetoken.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package devicetoken
 
@@ -19,6 +19,10 @@ const (
 	FieldLastRequest = "last_request"
 	// FieldPollInterval holds the string denoting the poll_interval field in the database.
 	FieldPollInterval = "poll_interval"
+	// FieldCodeChallenge holds the string denoting the code_challenge field in the database.
+	FieldCodeChallenge = "code_challenge"
+	// FieldCodeChallengeMethod holds the string denoting the code_challenge_method field in the database.
+	FieldCodeChallengeMethod = "code_challenge_method"
 	// Table holds the table name of the devicetoken in the database.
 	Table = "device_tokens"
 )
@@ -32,6 +36,8 @@ var Columns = []string{
 	FieldExpiry,
 	FieldLastRequest,
 	FieldPollInterval,
+	FieldCodeChallenge,
+	FieldCodeChallengeMethod,
 }
 
 // ValidColumn reports if the column name is valid (part of the table columns).
@@ -49,4 +55,8 @@ var (
 	DeviceCodeValidator func(string) error
 	// StatusValidator is a validator for the "status" field. It is called by the builders before save.
 	StatusValidator func(string) error
+	// DefaultCodeChallenge holds the default value on creation for the "code_challenge" field.
+	DefaultCodeChallenge string
+	// DefaultCodeChallengeMethod holds the default value on creation for the "code_challenge_method" field.
+	DefaultCodeChallengeMethod string
 )
diff --git a/storage/ent/db/devicetoken/where.go b/storage/ent/db/devicetoken/where.go
index b22879a6..a8e33f1e 100644
--- a/storage/ent/db/devicetoken/where.go
+++ b/storage/ent/db/devicetoken/where.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package devicetoken
 
@@ -33,12 +33,6 @@ func IDNEQ(id int) predicate.DeviceToken {
 // IDIn applies the In predicate on the ID field.
 func IDIn(ids ...int) predicate.DeviceToken {
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -50,12 +44,6 @@ func IDIn(ids ...int) predicate.DeviceToken {
 // IDNotIn applies the NotIn predicate on the ID field.
 func IDNotIn(ids ...int) predicate.DeviceToken {
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -134,6 +122,20 @@ func PollInterval(v int) predicate.DeviceToken {
 	})
 }
 
+// CodeChallenge applies equality check predicate on the "code_challenge" field. It's identical to CodeChallengeEQ.
+func CodeChallenge(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.EQ(s.C(FieldCodeChallenge), v))
+	})
+}
+
+// CodeChallengeMethod applies equality check predicate on the "code_challenge_method" field. It's identical to CodeChallengeMethodEQ.
+func CodeChallengeMethod(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.EQ(s.C(FieldCodeChallengeMethod), v))
+	})
+}
+
 // DeviceCodeEQ applies the EQ predicate on the "device_code" field.
 func DeviceCodeEQ(v string) predicate.DeviceToken {
 	return predicate.DeviceToken(func(s *sql.Selector) {
@@ -155,12 +157,6 @@ func DeviceCodeIn(vs ...string) predicate.DeviceToken {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldDeviceCode), v...))
 	})
 }
@@ -172,12 +168,6 @@ func DeviceCodeNotIn(vs ...string) predicate.DeviceToken {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldDeviceCode), v...))
 	})
 }
@@ -266,12 +256,6 @@ func StatusIn(vs ...string) predicate.DeviceToken {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldStatus), v...))
 	})
 }
@@ -283,12 +267,6 @@ func StatusNotIn(vs ...string) predicate.DeviceToken {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldStatus), v...))
 	})
 }
@@ -377,12 +355,6 @@ func TokenIn(vs ...[]byte) predicate.DeviceToken {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldToken), v...))
 	})
 }
@@ -394,12 +366,6 @@ func TokenNotIn(vs ...[]byte) predicate.DeviceToken {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldToken), v...))
 	})
 }
@@ -467,12 +433,6 @@ func ExpiryIn(vs ...time.Time) predicate.DeviceToken {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldExpiry), v...))
 	})
 }
@@ -484,12 +444,6 @@ func ExpiryNotIn(vs ...time.Time) predicate.DeviceToken {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldExpiry), v...))
 	})
 }
@@ -543,12 +497,6 @@ func LastRequestIn(vs ...time.Time) predicate.DeviceToken {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldLastRequest), v...))
 	})
 }
@@ -560,12 +508,6 @@ func LastRequestNotIn(vs ...time.Time) predicate.DeviceToken {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldLastRequest), v...))
 	})
 }
@@ -619,12 +561,6 @@ func PollIntervalIn(vs ...int) predicate.DeviceToken {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldPollInterval), v...))
 	})
 }
@@ -636,12 +572,6 @@ func PollIntervalNotIn(vs ...int) predicate.DeviceToken {
 		v[i] = vs[i]
 	}
 	return predicate.DeviceToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldPollInterval), v...))
 	})
 }
@@ -674,6 +604,204 @@ func PollIntervalLTE(v int) predicate.DeviceToken {
 	})
 }
 
+// CodeChallengeEQ applies the EQ predicate on the "code_challenge" field.
+func CodeChallengeEQ(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.EQ(s.C(FieldCodeChallenge), v))
+	})
+}
+
+// CodeChallengeNEQ applies the NEQ predicate on the "code_challenge" field.
+func CodeChallengeNEQ(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.NEQ(s.C(FieldCodeChallenge), v))
+	})
+}
+
+// CodeChallengeIn applies the In predicate on the "code_challenge" field.
+func CodeChallengeIn(vs ...string) predicate.DeviceToken {
+	v := make([]interface{}, len(vs))
+	for i := range v {
+		v[i] = vs[i]
+	}
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.In(s.C(FieldCodeChallenge), v...))
+	})
+}
+
+// CodeChallengeNotIn applies the NotIn predicate on the "code_challenge" field.
+func CodeChallengeNotIn(vs ...string) predicate.DeviceToken {
+	v := make([]interface{}, len(vs))
+	for i := range v {
+		v[i] = vs[i]
+	}
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.NotIn(s.C(FieldCodeChallenge), v...))
+	})
+}
+
+// CodeChallengeGT applies the GT predicate on the "code_challenge" field.
+func CodeChallengeGT(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.GT(s.C(FieldCodeChallenge), v))
+	})
+}
+
+// CodeChallengeGTE applies the GTE predicate on the "code_challenge" field.
+func CodeChallengeGTE(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.GTE(s.C(FieldCodeChallenge), v))
+	})
+}
+
+// CodeChallengeLT applies the LT predicate on the "code_challenge" field.
+func CodeChallengeLT(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.LT(s.C(FieldCodeChallenge), v))
+	})
+}
+
+// CodeChallengeLTE applies the LTE predicate on the "code_challenge" field.
+func CodeChallengeLTE(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.LTE(s.C(FieldCodeChallenge), v))
+	})
+}
+
+// CodeChallengeContains applies the Contains predicate on the "code_challenge" field.
+func CodeChallengeContains(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.Contains(s.C(FieldCodeChallenge), v))
+	})
+}
+
+// CodeChallengeHasPrefix applies the HasPrefix predicate on the "code_challenge" field.
+func CodeChallengeHasPrefix(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.HasPrefix(s.C(FieldCodeChallenge), v))
+	})
+}
+
+// CodeChallengeHasSuffix applies the HasSuffix predicate on the "code_challenge" field.
+func CodeChallengeHasSuffix(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.HasSuffix(s.C(FieldCodeChallenge), v))
+	})
+}
+
+// CodeChallengeEqualFold applies the EqualFold predicate on the "code_challenge" field.
+func CodeChallengeEqualFold(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.EqualFold(s.C(FieldCodeChallenge), v))
+	})
+}
+
+// CodeChallengeContainsFold applies the ContainsFold predicate on the "code_challenge" field.
+func CodeChallengeContainsFold(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.ContainsFold(s.C(FieldCodeChallenge), v))
+	})
+}
+
+// CodeChallengeMethodEQ applies the EQ predicate on the "code_challenge_method" field.
+func CodeChallengeMethodEQ(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.EQ(s.C(FieldCodeChallengeMethod), v))
+	})
+}
+
+// CodeChallengeMethodNEQ applies the NEQ predicate on the "code_challenge_method" field.
+func CodeChallengeMethodNEQ(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.NEQ(s.C(FieldCodeChallengeMethod), v))
+	})
+}
+
+// CodeChallengeMethodIn applies the In predicate on the "code_challenge_method" field.
+func CodeChallengeMethodIn(vs ...string) predicate.DeviceToken {
+	v := make([]interface{}, len(vs))
+	for i := range v {
+		v[i] = vs[i]
+	}
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.In(s.C(FieldCodeChallengeMethod), v...))
+	})
+}
+
+// CodeChallengeMethodNotIn applies the NotIn predicate on the "code_challenge_method" field.
+func CodeChallengeMethodNotIn(vs ...string) predicate.DeviceToken {
+	v := make([]interface{}, len(vs))
+	for i := range v {
+		v[i] = vs[i]
+	}
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.NotIn(s.C(FieldCodeChallengeMethod), v...))
+	})
+}
+
+// CodeChallengeMethodGT applies the GT predicate on the "code_challenge_method" field.
+func CodeChallengeMethodGT(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.GT(s.C(FieldCodeChallengeMethod), v))
+	})
+}
+
+// CodeChallengeMethodGTE applies the GTE predicate on the "code_challenge_method" field.
+func CodeChallengeMethodGTE(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.GTE(s.C(FieldCodeChallengeMethod), v))
+	})
+}
+
+// CodeChallengeMethodLT applies the LT predicate on the "code_challenge_method" field.
+func CodeChallengeMethodLT(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.LT(s.C(FieldCodeChallengeMethod), v))
+	})
+}
+
+// CodeChallengeMethodLTE applies the LTE predicate on the "code_challenge_method" field.
+func CodeChallengeMethodLTE(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.LTE(s.C(FieldCodeChallengeMethod), v))
+	})
+}
+
+// CodeChallengeMethodContains applies the Contains predicate on the "code_challenge_method" field.
+func CodeChallengeMethodContains(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.Contains(s.C(FieldCodeChallengeMethod), v))
+	})
+}
+
+// CodeChallengeMethodHasPrefix applies the HasPrefix predicate on the "code_challenge_method" field.
+func CodeChallengeMethodHasPrefix(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.HasPrefix(s.C(FieldCodeChallengeMethod), v))
+	})
+}
+
+// CodeChallengeMethodHasSuffix applies the HasSuffix predicate on the "code_challenge_method" field.
+func CodeChallengeMethodHasSuffix(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.HasSuffix(s.C(FieldCodeChallengeMethod), v))
+	})
+}
+
+// CodeChallengeMethodEqualFold applies the EqualFold predicate on the "code_challenge_method" field.
+func CodeChallengeMethodEqualFold(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.EqualFold(s.C(FieldCodeChallengeMethod), v))
+	})
+}
+
+// CodeChallengeMethodContainsFold applies the ContainsFold predicate on the "code_challenge_method" field.
+func CodeChallengeMethodContainsFold(v string) predicate.DeviceToken {
+	return predicate.DeviceToken(func(s *sql.Selector) {
+		s.Where(sql.ContainsFold(s.C(FieldCodeChallengeMethod), v))
+	})
+}
+
 // And groups predicates with the AND operator between them.
 func And(predicates ...predicate.DeviceToken) predicate.DeviceToken {
 	return predicate.DeviceToken(func(s *sql.Selector) {
diff --git a/storage/ent/db/devicetoken_create.go b/storage/ent/db/devicetoken_create.go
index 42c86755..bbf67e5a 100644
--- a/storage/ent/db/devicetoken_create.go
+++ b/storage/ent/db/devicetoken_create.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -56,6 +56,34 @@ func (dtc *DeviceTokenCreate) SetPollInterval(i int) *DeviceTokenCreate {
 	return dtc
 }
 
+// SetCodeChallenge sets the "code_challenge" field.
+func (dtc *DeviceTokenCreate) SetCodeChallenge(s string) *DeviceTokenCreate {
+	dtc.mutation.SetCodeChallenge(s)
+	return dtc
+}
+
+// SetNillableCodeChallenge sets the "code_challenge" field if the given value is not nil.
+func (dtc *DeviceTokenCreate) SetNillableCodeChallenge(s *string) *DeviceTokenCreate {
+	if s != nil {
+		dtc.SetCodeChallenge(*s)
+	}
+	return dtc
+}
+
+// SetCodeChallengeMethod sets the "code_challenge_method" field.
+func (dtc *DeviceTokenCreate) SetCodeChallengeMethod(s string) *DeviceTokenCreate {
+	dtc.mutation.SetCodeChallengeMethod(s)
+	return dtc
+}
+
+// SetNillableCodeChallengeMethod sets the "code_challenge_method" field if the given value is not nil.
+func (dtc *DeviceTokenCreate) SetNillableCodeChallengeMethod(s *string) *DeviceTokenCreate {
+	if s != nil {
+		dtc.SetCodeChallengeMethod(*s)
+	}
+	return dtc
+}
+
 // Mutation returns the DeviceTokenMutation object of the builder.
 func (dtc *DeviceTokenCreate) Mutation() *DeviceTokenMutation {
 	return dtc.mutation
@@ -67,6 +95,7 @@ func (dtc *DeviceTokenCreate) Save(ctx context.Context) (*DeviceToken, error) {
 		err  error
 		node *DeviceToken
 	)
+	dtc.defaults()
 	if len(dtc.hooks) == 0 {
 		if err = dtc.check(); err != nil {
 			return nil, err
@@ -95,9 +124,15 @@ func (dtc *DeviceTokenCreate) Save(ctx context.Context) (*DeviceToken, error) {
 			}
 			mut = dtc.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, dtc.mutation); err != nil {
+		v, err := mut.Mutate(ctx, dtc.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*DeviceToken)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from DeviceTokenMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -124,6 +159,18 @@ func (dtc *DeviceTokenCreate) ExecX(ctx context.Context) {
 	}
 }
 
+// defaults sets the default values of the builder before save.
+func (dtc *DeviceTokenCreate) defaults() {
+	if _, ok := dtc.mutation.CodeChallenge(); !ok {
+		v := devicetoken.DefaultCodeChallenge
+		dtc.mutation.SetCodeChallenge(v)
+	}
+	if _, ok := dtc.mutation.CodeChallengeMethod(); !ok {
+		v := devicetoken.DefaultCodeChallengeMethod
+		dtc.mutation.SetCodeChallengeMethod(v)
+	}
+}
+
 // check runs all checks and user-defined validators on the builder.
 func (dtc *DeviceTokenCreate) check() error {
 	if _, ok := dtc.mutation.DeviceCode(); !ok {
@@ -151,6 +198,12 @@ func (dtc *DeviceTokenCreate) check() error {
 	if _, ok := dtc.mutation.PollInterval(); !ok {
 		return &ValidationError{Name: "poll_interval", err: errors.New(`db: missing required field "DeviceToken.poll_interval"`)}
 	}
+	if _, ok := dtc.mutation.CodeChallenge(); !ok {
+		return &ValidationError{Name: "code_challenge", err: errors.New(`db: missing required field "DeviceToken.code_challenge"`)}
+	}
+	if _, ok := dtc.mutation.CodeChallengeMethod(); !ok {
+		return &ValidationError{Name: "code_challenge_method", err: errors.New(`db: missing required field "DeviceToken.code_challenge_method"`)}
+	}
 	return nil
 }
 
@@ -158,7 +211,7 @@ func (dtc *DeviceTokenCreate) sqlSave(ctx context.Context) (*DeviceToken, error)
 	_node, _spec := dtc.createSpec()
 	if err := sqlgraph.CreateNode(ctx, dtc.driver, _spec); err != nil {
 		if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
@@ -226,6 +279,22 @@ func (dtc *DeviceTokenCreate) createSpec() (*DeviceToken, *sqlgraph.CreateSpec)
 		})
 		_node.PollInterval = value
 	}
+	if value, ok := dtc.mutation.CodeChallenge(); ok {
+		_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
+			Type:   field.TypeString,
+			Value:  value,
+			Column: devicetoken.FieldCodeChallenge,
+		})
+		_node.CodeChallenge = value
+	}
+	if value, ok := dtc.mutation.CodeChallengeMethod(); ok {
+		_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
+			Type:   field.TypeString,
+			Value:  value,
+			Column: devicetoken.FieldCodeChallengeMethod,
+		})
+		_node.CodeChallengeMethod = value
+	}
 	return _node, _spec
 }
 
@@ -243,6 +312,7 @@ func (dtcb *DeviceTokenCreateBulk) Save(ctx context.Context) ([]*DeviceToken, er
 	for i := range dtcb.builders {
 		func(i int, root context.Context) {
 			builder := dtcb.builders[i]
+			builder.defaults()
 			var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
 				mutation, ok := m.(*DeviceTokenMutation)
 				if !ok {
@@ -261,7 +331,7 @@ func (dtcb *DeviceTokenCreateBulk) Save(ctx context.Context) ([]*DeviceToken, er
 					// Invoke the actual operation on the latest mutation in the chain.
 					if err = sqlgraph.BatchCreate(ctx, dtcb.driver, spec); err != nil {
 						if sqlgraph.IsConstraintError(err) {
-							err = &ConstraintError{err.Error(), err}
+							err = &ConstraintError{msg: err.Error(), wrap: err}
 						}
 					}
 				}
@@ -269,11 +339,11 @@ func (dtcb *DeviceTokenCreateBulk) Save(ctx context.Context) ([]*DeviceToken, er
 					return nil, err
 				}
 				mutation.id = &nodes[i].ID
-				mutation.done = true
 				if specs[i].ID.Value != nil {
 					id := specs[i].ID.Value.(int64)
 					nodes[i].ID = int(id)
 				}
+				mutation.done = true
 				return nodes[i], nil
 			})
 			for i := len(builder.hooks) - 1; i >= 0; i-- {
diff --git a/storage/ent/db/devicetoken_delete.go b/storage/ent/db/devicetoken_delete.go
index f23cc50e..3c196aac 100644
--- a/storage/ent/db/devicetoken_delete.go
+++ b/storage/ent/db/devicetoken_delete.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -84,7 +84,11 @@ func (dtd *DeviceTokenDelete) sqlExec(ctx context.Context) (int, error) {
 			}
 		}
 	}
-	return sqlgraph.DeleteNodes(ctx, dtd.driver, _spec)
+	affected, err := sqlgraph.DeleteNodes(ctx, dtd.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	return affected, err
 }
 
 // DeviceTokenDeleteOne is the builder for deleting a single DeviceToken entity.
diff --git a/storage/ent/db/devicetoken_query.go b/storage/ent/db/devicetoken_query.go
index 07697c49..1860a841 100644
--- a/storage/ent/db/devicetoken_query.go
+++ b/storage/ent/db/devicetoken_query.go
@@ -1,10 +1,9 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"math"
 
@@ -264,15 +263,17 @@ func (dtq *DeviceTokenQuery) Clone() *DeviceTokenQuery {
 //		Scan(ctx, &v)
 //
 func (dtq *DeviceTokenQuery) GroupBy(field string, fields ...string) *DeviceTokenGroupBy {
-	group := &DeviceTokenGroupBy{config: dtq.config}
-	group.fields = append([]string{field}, fields...)
-	group.path = func(ctx context.Context) (prev *sql.Selector, err error) {
+	grbuild := &DeviceTokenGroupBy{config: dtq.config}
+	grbuild.fields = append([]string{field}, fields...)
+	grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
 		if err := dtq.prepareQuery(ctx); err != nil {
 			return nil, err
 		}
 		return dtq.sqlQuery(ctx), nil
 	}
-	return group
+	grbuild.label = devicetoken.Label
+	grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
+	return grbuild
 }
 
 // Select allows the selection one or more fields/columns for the given query,
@@ -290,7 +291,10 @@ func (dtq *DeviceTokenQuery) GroupBy(field string, fields ...string) *DeviceToke
 //
 func (dtq *DeviceTokenQuery) Select(fields ...string) *DeviceTokenSelect {
 	dtq.fields = append(dtq.fields, fields...)
-	return &DeviceTokenSelect{DeviceTokenQuery: dtq}
+	selbuild := &DeviceTokenSelect{DeviceTokenQuery: dtq}
+	selbuild.label = devicetoken.Label
+	selbuild.flds, selbuild.scan = &dtq.fields, selbuild.Scan
+	return selbuild
 }
 
 func (dtq *DeviceTokenQuery) prepareQuery(ctx context.Context) error {
@@ -309,23 +313,22 @@ func (dtq *DeviceTokenQuery) prepareQuery(ctx context.Context) error {
 	return nil
 }
 
-func (dtq *DeviceTokenQuery) sqlAll(ctx context.Context) ([]*DeviceToken, error) {
+func (dtq *DeviceTokenQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*DeviceToken, error) {
 	var (
 		nodes = []*DeviceToken{}
 		_spec = dtq.querySpec()
 	)
 	_spec.ScanValues = func(columns []string) ([]interface{}, error) {
-		node := &DeviceToken{config: dtq.config}
-		nodes = append(nodes, node)
-		return node.scanValues(columns)
+		return (*DeviceToken).scanValues(nil, columns)
 	}
 	_spec.Assign = func(columns []string, values []interface{}) error {
-		if len(nodes) == 0 {
-			return fmt.Errorf("db: Assign called without calling ScanValues")
-		}
-		node := nodes[len(nodes)-1]
+		node := &DeviceToken{config: dtq.config}
+		nodes = append(nodes, node)
 		return node.assignValues(columns, values)
 	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
 	if err := sqlgraph.QueryNodes(ctx, dtq.driver, _spec); err != nil {
 		return nil, err
 	}
@@ -435,6 +438,7 @@ func (dtq *DeviceTokenQuery) sqlQuery(ctx context.Context) *sql.Selector {
 // DeviceTokenGroupBy is the group-by builder for DeviceToken entities.
 type DeviceTokenGroupBy struct {
 	config
+	selector
 	fields []string
 	fns    []AggregateFunc
 	// intermediate query (i.e. traversal path).
@@ -458,209 +462,6 @@ func (dtgb *DeviceTokenGroupBy) Scan(ctx context.Context, v interface{}) error {
 	return dtgb.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (dtgb *DeviceTokenGroupBy) ScanX(ctx context.Context, v interface{}) {
-	if err := dtgb.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (dtgb *DeviceTokenGroupBy) Strings(ctx context.Context) ([]string, error) {
-	if len(dtgb.fields) > 1 {
-		return nil, errors.New("db: DeviceTokenGroupBy.Strings is not achievable when grouping more than 1 field")
-	}
-	var v []string
-	if err := dtgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (dtgb *DeviceTokenGroupBy) StringsX(ctx context.Context) []string {
-	v, err := dtgb.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (dtgb *DeviceTokenGroupBy) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = dtgb.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicetoken.Label}
-	default:
-		err = fmt.Errorf("db: DeviceTokenGroupBy.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (dtgb *DeviceTokenGroupBy) StringX(ctx context.Context) string {
-	v, err := dtgb.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (dtgb *DeviceTokenGroupBy) Ints(ctx context.Context) ([]int, error) {
-	if len(dtgb.fields) > 1 {
-		return nil, errors.New("db: DeviceTokenGroupBy.Ints is not achievable when grouping more than 1 field")
-	}
-	var v []int
-	if err := dtgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (dtgb *DeviceTokenGroupBy) IntsX(ctx context.Context) []int {
-	v, err := dtgb.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (dtgb *DeviceTokenGroupBy) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = dtgb.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicetoken.Label}
-	default:
-		err = fmt.Errorf("db: DeviceTokenGroupBy.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (dtgb *DeviceTokenGroupBy) IntX(ctx context.Context) int {
-	v, err := dtgb.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (dtgb *DeviceTokenGroupBy) Float64s(ctx context.Context) ([]float64, error) {
-	if len(dtgb.fields) > 1 {
-		return nil, errors.New("db: DeviceTokenGroupBy.Float64s is not achievable when grouping more than 1 field")
-	}
-	var v []float64
-	if err := dtgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (dtgb *DeviceTokenGroupBy) Float64sX(ctx context.Context) []float64 {
-	v, err := dtgb.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (dtgb *DeviceTokenGroupBy) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = dtgb.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicetoken.Label}
-	default:
-		err = fmt.Errorf("db: DeviceTokenGroupBy.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (dtgb *DeviceTokenGroupBy) Float64X(ctx context.Context) float64 {
-	v, err := dtgb.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (dtgb *DeviceTokenGroupBy) Bools(ctx context.Context) ([]bool, error) {
-	if len(dtgb.fields) > 1 {
-		return nil, errors.New("db: DeviceTokenGroupBy.Bools is not achievable when grouping more than 1 field")
-	}
-	var v []bool
-	if err := dtgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (dtgb *DeviceTokenGroupBy) BoolsX(ctx context.Context) []bool {
-	v, err := dtgb.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (dtgb *DeviceTokenGroupBy) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = dtgb.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicetoken.Label}
-	default:
-		err = fmt.Errorf("db: DeviceTokenGroupBy.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (dtgb *DeviceTokenGroupBy) BoolX(ctx context.Context) bool {
-	v, err := dtgb.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (dtgb *DeviceTokenGroupBy) sqlScan(ctx context.Context, v interface{}) error {
 	for _, f := range dtgb.fields {
 		if !devicetoken.ValidColumn(f) {
@@ -702,6 +503,7 @@ func (dtgb *DeviceTokenGroupBy) sqlQuery() *sql.Selector {
 // DeviceTokenSelect is the builder for selecting fields of DeviceToken entities.
 type DeviceTokenSelect struct {
 	*DeviceTokenQuery
+	selector
 	// intermediate query (i.e. traversal path).
 	sql *sql.Selector
 }
@@ -715,201 +517,6 @@ func (dts *DeviceTokenSelect) Scan(ctx context.Context, v interface{}) error {
 	return dts.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (dts *DeviceTokenSelect) ScanX(ctx context.Context, v interface{}) {
-	if err := dts.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from a selector. It is only allowed when selecting one field.
-func (dts *DeviceTokenSelect) Strings(ctx context.Context) ([]string, error) {
-	if len(dts.fields) > 1 {
-		return nil, errors.New("db: DeviceTokenSelect.Strings is not achievable when selecting more than 1 field")
-	}
-	var v []string
-	if err := dts.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (dts *DeviceTokenSelect) StringsX(ctx context.Context) []string {
-	v, err := dts.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a selector. It is only allowed when selecting one field.
-func (dts *DeviceTokenSelect) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = dts.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicetoken.Label}
-	default:
-		err = fmt.Errorf("db: DeviceTokenSelect.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (dts *DeviceTokenSelect) StringX(ctx context.Context) string {
-	v, err := dts.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from a selector. It is only allowed when selecting one field.
-func (dts *DeviceTokenSelect) Ints(ctx context.Context) ([]int, error) {
-	if len(dts.fields) > 1 {
-		return nil, errors.New("db: DeviceTokenSelect.Ints is not achievable when selecting more than 1 field")
-	}
-	var v []int
-	if err := dts.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (dts *DeviceTokenSelect) IntsX(ctx context.Context) []int {
-	v, err := dts.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a selector. It is only allowed when selecting one field.
-func (dts *DeviceTokenSelect) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = dts.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicetoken.Label}
-	default:
-		err = fmt.Errorf("db: DeviceTokenSelect.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (dts *DeviceTokenSelect) IntX(ctx context.Context) int {
-	v, err := dts.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
-func (dts *DeviceTokenSelect) Float64s(ctx context.Context) ([]float64, error) {
-	if len(dts.fields) > 1 {
-		return nil, errors.New("db: DeviceTokenSelect.Float64s is not achievable when selecting more than 1 field")
-	}
-	var v []float64
-	if err := dts.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (dts *DeviceTokenSelect) Float64sX(ctx context.Context) []float64 {
-	v, err := dts.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
-func (dts *DeviceTokenSelect) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = dts.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicetoken.Label}
-	default:
-		err = fmt.Errorf("db: DeviceTokenSelect.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (dts *DeviceTokenSelect) Float64X(ctx context.Context) float64 {
-	v, err := dts.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from a selector. It is only allowed when selecting one field.
-func (dts *DeviceTokenSelect) Bools(ctx context.Context) ([]bool, error) {
-	if len(dts.fields) > 1 {
-		return nil, errors.New("db: DeviceTokenSelect.Bools is not achievable when selecting more than 1 field")
-	}
-	var v []bool
-	if err := dts.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (dts *DeviceTokenSelect) BoolsX(ctx context.Context) []bool {
-	v, err := dts.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a selector. It is only allowed when selecting one field.
-func (dts *DeviceTokenSelect) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = dts.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{devicetoken.Label}
-	default:
-		err = fmt.Errorf("db: DeviceTokenSelect.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (dts *DeviceTokenSelect) BoolX(ctx context.Context) bool {
-	v, err := dts.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (dts *DeviceTokenSelect) sqlScan(ctx context.Context, v interface{}) error {
 	rows := &sql.Rows{}
 	query, args := dts.sql.Query()
diff --git a/storage/ent/db/devicetoken_update.go b/storage/ent/db/devicetoken_update.go
index bf9d2993..cc0b92f5 100644
--- a/storage/ent/db/devicetoken_update.go
+++ b/storage/ent/db/devicetoken_update.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -77,6 +77,34 @@ func (dtu *DeviceTokenUpdate) AddPollInterval(i int) *DeviceTokenUpdate {
 	return dtu
 }
 
+// SetCodeChallenge sets the "code_challenge" field.
+func (dtu *DeviceTokenUpdate) SetCodeChallenge(s string) *DeviceTokenUpdate {
+	dtu.mutation.SetCodeChallenge(s)
+	return dtu
+}
+
+// SetNillableCodeChallenge sets the "code_challenge" field if the given value is not nil.
+func (dtu *DeviceTokenUpdate) SetNillableCodeChallenge(s *string) *DeviceTokenUpdate {
+	if s != nil {
+		dtu.SetCodeChallenge(*s)
+	}
+	return dtu
+}
+
+// SetCodeChallengeMethod sets the "code_challenge_method" field.
+func (dtu *DeviceTokenUpdate) SetCodeChallengeMethod(s string) *DeviceTokenUpdate {
+	dtu.mutation.SetCodeChallengeMethod(s)
+	return dtu
+}
+
+// SetNillableCodeChallengeMethod sets the "code_challenge_method" field if the given value is not nil.
+func (dtu *DeviceTokenUpdate) SetNillableCodeChallengeMethod(s *string) *DeviceTokenUpdate {
+	if s != nil {
+		dtu.SetCodeChallengeMethod(*s)
+	}
+	return dtu
+}
+
 // Mutation returns the DeviceTokenMutation object of the builder.
 func (dtu *DeviceTokenUpdate) Mutation() *DeviceTokenMutation {
 	return dtu.mutation
@@ -230,11 +258,25 @@ func (dtu *DeviceTokenUpdate) sqlSave(ctx context.Context) (n int, err error) {
 			Column: devicetoken.FieldPollInterval,
 		})
 	}
+	if value, ok := dtu.mutation.CodeChallenge(); ok {
+		_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
+			Type:   field.TypeString,
+			Value:  value,
+			Column: devicetoken.FieldCodeChallenge,
+		})
+	}
+	if value, ok := dtu.mutation.CodeChallengeMethod(); ok {
+		_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
+			Type:   field.TypeString,
+			Value:  value,
+			Column: devicetoken.FieldCodeChallengeMethod,
+		})
+	}
 	if n, err = sqlgraph.UpdateNodes(ctx, dtu.driver, _spec); err != nil {
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{devicetoken.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return 0, err
 	}
@@ -298,6 +340,34 @@ func (dtuo *DeviceTokenUpdateOne) AddPollInterval(i int) *DeviceTokenUpdateOne {
 	return dtuo
 }
 
+// SetCodeChallenge sets the "code_challenge" field.
+func (dtuo *DeviceTokenUpdateOne) SetCodeChallenge(s string) *DeviceTokenUpdateOne {
+	dtuo.mutation.SetCodeChallenge(s)
+	return dtuo
+}
+
+// SetNillableCodeChallenge sets the "code_challenge" field if the given value is not nil.
+func (dtuo *DeviceTokenUpdateOne) SetNillableCodeChallenge(s *string) *DeviceTokenUpdateOne {
+	if s != nil {
+		dtuo.SetCodeChallenge(*s)
+	}
+	return dtuo
+}
+
+// SetCodeChallengeMethod sets the "code_challenge_method" field.
+func (dtuo *DeviceTokenUpdateOne) SetCodeChallengeMethod(s string) *DeviceTokenUpdateOne {
+	dtuo.mutation.SetCodeChallengeMethod(s)
+	return dtuo
+}
+
+// SetNillableCodeChallengeMethod sets the "code_challenge_method" field if the given value is not nil.
+func (dtuo *DeviceTokenUpdateOne) SetNillableCodeChallengeMethod(s *string) *DeviceTokenUpdateOne {
+	if s != nil {
+		dtuo.SetCodeChallengeMethod(*s)
+	}
+	return dtuo
+}
+
 // Mutation returns the DeviceTokenMutation object of the builder.
 func (dtuo *DeviceTokenUpdateOne) Mutation() *DeviceTokenMutation {
 	return dtuo.mutation
@@ -341,9 +411,15 @@ func (dtuo *DeviceTokenUpdateOne) Save(ctx context.Context) (*DeviceToken, error
 			}
 			mut = dtuo.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, dtuo.mutation); err != nil {
+		v, err := mut.Mutate(ctx, dtuo.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*DeviceToken)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from DeviceTokenMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -475,6 +551,20 @@ func (dtuo *DeviceTokenUpdateOne) sqlSave(ctx context.Context) (_node *DeviceTok
 			Column: devicetoken.FieldPollInterval,
 		})
 	}
+	if value, ok := dtuo.mutation.CodeChallenge(); ok {
+		_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
+			Type:   field.TypeString,
+			Value:  value,
+			Column: devicetoken.FieldCodeChallenge,
+		})
+	}
+	if value, ok := dtuo.mutation.CodeChallengeMethod(); ok {
+		_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
+			Type:   field.TypeString,
+			Value:  value,
+			Column: devicetoken.FieldCodeChallengeMethod,
+		})
+	}
 	_node = &DeviceToken{config: dtuo.config}
 	_spec.Assign = _node.assignValues
 	_spec.ScanValues = _node.scanValues
@@ -482,7 +572,7 @@ func (dtuo *DeviceTokenUpdateOne) sqlSave(ctx context.Context) (_node *DeviceTok
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{devicetoken.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
diff --git a/storage/ent/db/ent.go b/storage/ent/db/ent.go
index 15a183a2..ed76b32b 100644
--- a/storage/ent/db/ent.go
+++ b/storage/ent/db/ent.go
@@ -1,13 +1,15 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
 import (
+	"context"
 	"errors"
 	"fmt"
 
 	"entgo.io/ent"
 	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
 	"github.com/dexidp/dex/storage/ent/db/authcode"
 	"github.com/dexidp/dex/storage/ent/db/authrequest"
 	"github.com/dexidp/dex/storage/ent/db/connector"
@@ -275,3 +277,208 @@ func IsConstraintError(err error) bool {
 	var e *ConstraintError
 	return errors.As(err, &e)
 }
+
+// selector embedded by the different Select/GroupBy builders.
+type selector struct {
+	label string
+	flds  *[]string
+	scan  func(context.Context, interface{}) error
+}
+
+// ScanX is like Scan, but panics if an error occurs.
+func (s *selector) ScanX(ctx context.Context, v interface{}) {
+	if err := s.scan(ctx, v); err != nil {
+		panic(err)
+	}
+}
+
+// Strings returns list of strings from a selector. It is only allowed when selecting one field.
+func (s *selector) Strings(ctx context.Context) ([]string, error) {
+	if len(*s.flds) > 1 {
+		return nil, errors.New("db: Strings is not achievable when selecting more than 1 field")
+	}
+	var v []string
+	if err := s.scan(ctx, &v); err != nil {
+		return nil, err
+	}
+	return v, nil
+}
+
+// StringsX is like Strings, but panics if an error occurs.
+func (s *selector) StringsX(ctx context.Context) []string {
+	v, err := s.Strings(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// String returns a single string from a selector. It is only allowed when selecting one field.
+func (s *selector) String(ctx context.Context) (_ string, err error) {
+	var v []string
+	if v, err = s.Strings(ctx); err != nil {
+		return
+	}
+	switch len(v) {
+	case 1:
+		return v[0], nil
+	case 0:
+		err = &NotFoundError{s.label}
+	default:
+		err = fmt.Errorf("db: Strings returned %d results when one was expected", len(v))
+	}
+	return
+}
+
+// StringX is like String, but panics if an error occurs.
+func (s *selector) StringX(ctx context.Context) string {
+	v, err := s.String(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Ints returns list of ints from a selector. It is only allowed when selecting one field.
+func (s *selector) Ints(ctx context.Context) ([]int, error) {
+	if len(*s.flds) > 1 {
+		return nil, errors.New("db: Ints is not achievable when selecting more than 1 field")
+	}
+	var v []int
+	if err := s.scan(ctx, &v); err != nil {
+		return nil, err
+	}
+	return v, nil
+}
+
+// IntsX is like Ints, but panics if an error occurs.
+func (s *selector) IntsX(ctx context.Context) []int {
+	v, err := s.Ints(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Int returns a single int from a selector. It is only allowed when selecting one field.
+func (s *selector) Int(ctx context.Context) (_ int, err error) {
+	var v []int
+	if v, err = s.Ints(ctx); err != nil {
+		return
+	}
+	switch len(v) {
+	case 1:
+		return v[0], nil
+	case 0:
+		err = &NotFoundError{s.label}
+	default:
+		err = fmt.Errorf("db: Ints returned %d results when one was expected", len(v))
+	}
+	return
+}
+
+// IntX is like Int, but panics if an error occurs.
+func (s *selector) IntX(ctx context.Context) int {
+	v, err := s.Int(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
+func (s *selector) Float64s(ctx context.Context) ([]float64, error) {
+	if len(*s.flds) > 1 {
+		return nil, errors.New("db: Float64s is not achievable when selecting more than 1 field")
+	}
+	var v []float64
+	if err := s.scan(ctx, &v); err != nil {
+		return nil, err
+	}
+	return v, nil
+}
+
+// Float64sX is like Float64s, but panics if an error occurs.
+func (s *selector) Float64sX(ctx context.Context) []float64 {
+	v, err := s.Float64s(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
+func (s *selector) Float64(ctx context.Context) (_ float64, err error) {
+	var v []float64
+	if v, err = s.Float64s(ctx); err != nil {
+		return
+	}
+	switch len(v) {
+	case 1:
+		return v[0], nil
+	case 0:
+		err = &NotFoundError{s.label}
+	default:
+		err = fmt.Errorf("db: Float64s returned %d results when one was expected", len(v))
+	}
+	return
+}
+
+// Float64X is like Float64, but panics if an error occurs.
+func (s *selector) Float64X(ctx context.Context) float64 {
+	v, err := s.Float64(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Bools returns list of bools from a selector. It is only allowed when selecting one field.
+func (s *selector) Bools(ctx context.Context) ([]bool, error) {
+	if len(*s.flds) > 1 {
+		return nil, errors.New("db: Bools is not achievable when selecting more than 1 field")
+	}
+	var v []bool
+	if err := s.scan(ctx, &v); err != nil {
+		return nil, err
+	}
+	return v, nil
+}
+
+// BoolsX is like Bools, but panics if an error occurs.
+func (s *selector) BoolsX(ctx context.Context) []bool {
+	v, err := s.Bools(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Bool returns a single bool from a selector. It is only allowed when selecting one field.
+func (s *selector) Bool(ctx context.Context) (_ bool, err error) {
+	var v []bool
+	if v, err = s.Bools(ctx); err != nil {
+		return
+	}
+	switch len(v) {
+	case 1:
+		return v[0], nil
+	case 0:
+		err = &NotFoundError{s.label}
+	default:
+		err = fmt.Errorf("db: Bools returned %d results when one was expected", len(v))
+	}
+	return
+}
+
+// BoolX is like Bool, but panics if an error occurs.
+func (s *selector) BoolX(ctx context.Context) bool {
+	v, err := s.Bool(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// queryHook describes an internal hook for the different sqlAll methods.
+type queryHook func(context.Context, *sqlgraph.QuerySpec)
diff --git a/storage/ent/db/enttest/enttest.go b/storage/ent/db/enttest/enttest.go
index 7dffdd1b..ecbb02d9 100644
--- a/storage/ent/db/enttest/enttest.go
+++ b/storage/ent/db/enttest/enttest.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package enttest
 
@@ -10,6 +10,7 @@ import (
 	_ "github.com/dexidp/dex/storage/ent/db/runtime"
 
 	"entgo.io/ent/dialect/sql/schema"
+	"github.com/dexidp/dex/storage/ent/db/migrate"
 )
 
 type (
@@ -59,10 +60,7 @@ func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *db.Cli
 		t.Error(err)
 		t.FailNow()
 	}
-	if err := c.Schema.Create(context.Background(), o.migrateOpts...); err != nil {
-		t.Error(err)
-		t.FailNow()
-	}
+	migrateSchema(t, c, o)
 	return c
 }
 
@@ -70,9 +68,17 @@ func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *db.Cli
 func NewClient(t TestingT, opts ...Option) *db.Client {
 	o := newOptions(opts)
 	c := db.NewClient(o.opts...)
-	if err := c.Schema.Create(context.Background(), o.migrateOpts...); err != nil {
+	migrateSchema(t, c, o)
+	return c
+}
+func migrateSchema(t TestingT, c *db.Client, o *options) {
+	tables, err := schema.CopyTables(migrate.Tables)
+	if err != nil {
+		t.Error(err)
+		t.FailNow()
+	}
+	if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil {
 		t.Error(err)
 		t.FailNow()
 	}
-	return c
 }
diff --git a/storage/ent/db/hook/hook.go b/storage/ent/db/hook/hook.go
index 8a7d8e40..856e5e59 100644
--- a/storage/ent/db/hook/hook.go
+++ b/storage/ent/db/hook/hook.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package hook
 
diff --git a/storage/ent/db/keys.go b/storage/ent/db/keys.go
index acdd8257..d307ad8e 100644
--- a/storage/ent/db/keys.go
+++ b/storage/ent/db/keys.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -11,7 +11,7 @@ import (
 	"entgo.io/ent/dialect/sql"
 	"github.com/dexidp/dex/storage"
 	"github.com/dexidp/dex/storage/ent/db/keys"
-	"gopkg.in/square/go-jose.v2"
+	jose "gopkg.in/square/go-jose.v2"
 )
 
 // Keys is the model entity for the Keys schema.
@@ -106,11 +106,11 @@ func (k *Keys) Update() *KeysUpdateOne {
 // Unwrap unwraps the Keys entity that was returned from a transaction after it was closed,
 // so that all future queries will be executed through the driver which created the transaction.
 func (k *Keys) Unwrap() *Keys {
-	tx, ok := k.config.driver.(*txDriver)
+	_tx, ok := k.config.driver.(*txDriver)
 	if !ok {
 		panic("db: Keys is not a transactional entity")
 	}
-	k.config.driver = tx.drv
+	k.config.driver = _tx.drv
 	return k
 }
 
@@ -118,14 +118,17 @@ func (k *Keys) Unwrap() *Keys {
 func (k *Keys) String() string {
 	var builder strings.Builder
 	builder.WriteString("Keys(")
-	builder.WriteString(fmt.Sprintf("id=%v", k.ID))
-	builder.WriteString(", verification_keys=")
+	builder.WriteString(fmt.Sprintf("id=%v, ", k.ID))
+	builder.WriteString("verification_keys=")
 	builder.WriteString(fmt.Sprintf("%v", k.VerificationKeys))
-	builder.WriteString(", signing_key=")
+	builder.WriteString(", ")
+	builder.WriteString("signing_key=")
 	builder.WriteString(fmt.Sprintf("%v", k.SigningKey))
-	builder.WriteString(", signing_key_pub=")
+	builder.WriteString(", ")
+	builder.WriteString("signing_key_pub=")
 	builder.WriteString(fmt.Sprintf("%v", k.SigningKeyPub))
-	builder.WriteString(", next_rotation=")
+	builder.WriteString(", ")
+	builder.WriteString("next_rotation=")
 	builder.WriteString(k.NextRotation.Format(time.ANSIC))
 	builder.WriteByte(')')
 	return builder.String()
diff --git a/storage/ent/db/keys/keys.go b/storage/ent/db/keys/keys.go
index b877a2f6..eb96d92a 100644
--- a/storage/ent/db/keys/keys.go
+++ b/storage/ent/db/keys/keys.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package keys
 
diff --git a/storage/ent/db/keys/where.go b/storage/ent/db/keys/where.go
index 55aa8ce3..f918579d 100644
--- a/storage/ent/db/keys/where.go
+++ b/storage/ent/db/keys/where.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package keys
 
@@ -33,12 +33,6 @@ func IDNEQ(id string) predicate.Keys {
 // IDIn applies the In predicate on the ID field.
 func IDIn(ids ...string) predicate.Keys {
 	return predicate.Keys(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -50,12 +44,6 @@ func IDIn(ids ...string) predicate.Keys {
 // IDNotIn applies the NotIn predicate on the ID field.
 func IDNotIn(ids ...string) predicate.Keys {
 	return predicate.Keys(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -120,12 +108,6 @@ func NextRotationIn(vs ...time.Time) predicate.Keys {
 		v[i] = vs[i]
 	}
 	return predicate.Keys(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldNextRotation), v...))
 	})
 }
@@ -137,12 +119,6 @@ func NextRotationNotIn(vs ...time.Time) predicate.Keys {
 		v[i] = vs[i]
 	}
 	return predicate.Keys(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldNextRotation), v...))
 	})
 }
diff --git a/storage/ent/db/keys_create.go b/storage/ent/db/keys_create.go
index 2b37b581..818ca278 100644
--- a/storage/ent/db/keys_create.go
+++ b/storage/ent/db/keys_create.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -12,7 +12,7 @@ import (
 	"entgo.io/ent/schema/field"
 	"github.com/dexidp/dex/storage"
 	"github.com/dexidp/dex/storage/ent/db/keys"
-	"gopkg.in/square/go-jose.v2"
+	jose "gopkg.in/square/go-jose.v2"
 )
 
 // KeysCreate is the builder for creating a Keys entity.
@@ -91,9 +91,15 @@ func (kc *KeysCreate) Save(ctx context.Context) (*Keys, error) {
 			}
 			mut = kc.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, kc.mutation); err != nil {
+		v, err := mut.Mutate(ctx, kc.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*Keys)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from KeysMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -146,7 +152,7 @@ func (kc *KeysCreate) sqlSave(ctx context.Context) (*Keys, error) {
 	_node, _spec := kc.createSpec()
 	if err := sqlgraph.CreateNode(ctx, kc.driver, _spec); err != nil {
 		if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
@@ -242,7 +248,7 @@ func (kcb *KeysCreateBulk) Save(ctx context.Context) ([]*Keys, error) {
 					// Invoke the actual operation on the latest mutation in the chain.
 					if err = sqlgraph.BatchCreate(ctx, kcb.driver, spec); err != nil {
 						if sqlgraph.IsConstraintError(err) {
-							err = &ConstraintError{err.Error(), err}
+							err = &ConstraintError{msg: err.Error(), wrap: err}
 						}
 					}
 				}
diff --git a/storage/ent/db/keys_delete.go b/storage/ent/db/keys_delete.go
index 6950c257..5bcf970f 100644
--- a/storage/ent/db/keys_delete.go
+++ b/storage/ent/db/keys_delete.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -84,7 +84,11 @@ func (kd *KeysDelete) sqlExec(ctx context.Context) (int, error) {
 			}
 		}
 	}
-	return sqlgraph.DeleteNodes(ctx, kd.driver, _spec)
+	affected, err := sqlgraph.DeleteNodes(ctx, kd.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	return affected, err
 }
 
 // KeysDeleteOne is the builder for deleting a single Keys entity.
diff --git a/storage/ent/db/keys_query.go b/storage/ent/db/keys_query.go
index c2dfc173..7d9ea908 100644
--- a/storage/ent/db/keys_query.go
+++ b/storage/ent/db/keys_query.go
@@ -1,10 +1,9 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"math"
 
@@ -264,15 +263,17 @@ func (kq *KeysQuery) Clone() *KeysQuery {
 //		Scan(ctx, &v)
 //
 func (kq *KeysQuery) GroupBy(field string, fields ...string) *KeysGroupBy {
-	group := &KeysGroupBy{config: kq.config}
-	group.fields = append([]string{field}, fields...)
-	group.path = func(ctx context.Context) (prev *sql.Selector, err error) {
+	grbuild := &KeysGroupBy{config: kq.config}
+	grbuild.fields = append([]string{field}, fields...)
+	grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
 		if err := kq.prepareQuery(ctx); err != nil {
 			return nil, err
 		}
 		return kq.sqlQuery(ctx), nil
 	}
-	return group
+	grbuild.label = keys.Label
+	grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
+	return grbuild
 }
 
 // Select allows the selection one or more fields/columns for the given query,
@@ -290,7 +291,10 @@ func (kq *KeysQuery) GroupBy(field string, fields ...string) *KeysGroupBy {
 //
 func (kq *KeysQuery) Select(fields ...string) *KeysSelect {
 	kq.fields = append(kq.fields, fields...)
-	return &KeysSelect{KeysQuery: kq}
+	selbuild := &KeysSelect{KeysQuery: kq}
+	selbuild.label = keys.Label
+	selbuild.flds, selbuild.scan = &kq.fields, selbuild.Scan
+	return selbuild
 }
 
 func (kq *KeysQuery) prepareQuery(ctx context.Context) error {
@@ -309,23 +313,22 @@ func (kq *KeysQuery) prepareQuery(ctx context.Context) error {
 	return nil
 }
 
-func (kq *KeysQuery) sqlAll(ctx context.Context) ([]*Keys, error) {
+func (kq *KeysQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Keys, error) {
 	var (
 		nodes = []*Keys{}
 		_spec = kq.querySpec()
 	)
 	_spec.ScanValues = func(columns []string) ([]interface{}, error) {
-		node := &Keys{config: kq.config}
-		nodes = append(nodes, node)
-		return node.scanValues(columns)
+		return (*Keys).scanValues(nil, columns)
 	}
 	_spec.Assign = func(columns []string, values []interface{}) error {
-		if len(nodes) == 0 {
-			return fmt.Errorf("db: Assign called without calling ScanValues")
-		}
-		node := nodes[len(nodes)-1]
+		node := &Keys{config: kq.config}
+		nodes = append(nodes, node)
 		return node.assignValues(columns, values)
 	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
 	if err := sqlgraph.QueryNodes(ctx, kq.driver, _spec); err != nil {
 		return nil, err
 	}
@@ -435,6 +438,7 @@ func (kq *KeysQuery) sqlQuery(ctx context.Context) *sql.Selector {
 // KeysGroupBy is the group-by builder for Keys entities.
 type KeysGroupBy struct {
 	config
+	selector
 	fields []string
 	fns    []AggregateFunc
 	// intermediate query (i.e. traversal path).
@@ -458,209 +462,6 @@ func (kgb *KeysGroupBy) Scan(ctx context.Context, v interface{}) error {
 	return kgb.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (kgb *KeysGroupBy) ScanX(ctx context.Context, v interface{}) {
-	if err := kgb.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (kgb *KeysGroupBy) Strings(ctx context.Context) ([]string, error) {
-	if len(kgb.fields) > 1 {
-		return nil, errors.New("db: KeysGroupBy.Strings is not achievable when grouping more than 1 field")
-	}
-	var v []string
-	if err := kgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (kgb *KeysGroupBy) StringsX(ctx context.Context) []string {
-	v, err := kgb.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (kgb *KeysGroupBy) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = kgb.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{keys.Label}
-	default:
-		err = fmt.Errorf("db: KeysGroupBy.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (kgb *KeysGroupBy) StringX(ctx context.Context) string {
-	v, err := kgb.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (kgb *KeysGroupBy) Ints(ctx context.Context) ([]int, error) {
-	if len(kgb.fields) > 1 {
-		return nil, errors.New("db: KeysGroupBy.Ints is not achievable when grouping more than 1 field")
-	}
-	var v []int
-	if err := kgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (kgb *KeysGroupBy) IntsX(ctx context.Context) []int {
-	v, err := kgb.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (kgb *KeysGroupBy) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = kgb.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{keys.Label}
-	default:
-		err = fmt.Errorf("db: KeysGroupBy.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (kgb *KeysGroupBy) IntX(ctx context.Context) int {
-	v, err := kgb.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (kgb *KeysGroupBy) Float64s(ctx context.Context) ([]float64, error) {
-	if len(kgb.fields) > 1 {
-		return nil, errors.New("db: KeysGroupBy.Float64s is not achievable when grouping more than 1 field")
-	}
-	var v []float64
-	if err := kgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (kgb *KeysGroupBy) Float64sX(ctx context.Context) []float64 {
-	v, err := kgb.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (kgb *KeysGroupBy) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = kgb.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{keys.Label}
-	default:
-		err = fmt.Errorf("db: KeysGroupBy.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (kgb *KeysGroupBy) Float64X(ctx context.Context) float64 {
-	v, err := kgb.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (kgb *KeysGroupBy) Bools(ctx context.Context) ([]bool, error) {
-	if len(kgb.fields) > 1 {
-		return nil, errors.New("db: KeysGroupBy.Bools is not achievable when grouping more than 1 field")
-	}
-	var v []bool
-	if err := kgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (kgb *KeysGroupBy) BoolsX(ctx context.Context) []bool {
-	v, err := kgb.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (kgb *KeysGroupBy) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = kgb.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{keys.Label}
-	default:
-		err = fmt.Errorf("db: KeysGroupBy.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (kgb *KeysGroupBy) BoolX(ctx context.Context) bool {
-	v, err := kgb.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (kgb *KeysGroupBy) sqlScan(ctx context.Context, v interface{}) error {
 	for _, f := range kgb.fields {
 		if !keys.ValidColumn(f) {
@@ -702,6 +503,7 @@ func (kgb *KeysGroupBy) sqlQuery() *sql.Selector {
 // KeysSelect is the builder for selecting fields of Keys entities.
 type KeysSelect struct {
 	*KeysQuery
+	selector
 	// intermediate query (i.e. traversal path).
 	sql *sql.Selector
 }
@@ -715,201 +517,6 @@ func (ks *KeysSelect) Scan(ctx context.Context, v interface{}) error {
 	return ks.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (ks *KeysSelect) ScanX(ctx context.Context, v interface{}) {
-	if err := ks.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from a selector. It is only allowed when selecting one field.
-func (ks *KeysSelect) Strings(ctx context.Context) ([]string, error) {
-	if len(ks.fields) > 1 {
-		return nil, errors.New("db: KeysSelect.Strings is not achievable when selecting more than 1 field")
-	}
-	var v []string
-	if err := ks.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (ks *KeysSelect) StringsX(ctx context.Context) []string {
-	v, err := ks.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a selector. It is only allowed when selecting one field.
-func (ks *KeysSelect) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = ks.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{keys.Label}
-	default:
-		err = fmt.Errorf("db: KeysSelect.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (ks *KeysSelect) StringX(ctx context.Context) string {
-	v, err := ks.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from a selector. It is only allowed when selecting one field.
-func (ks *KeysSelect) Ints(ctx context.Context) ([]int, error) {
-	if len(ks.fields) > 1 {
-		return nil, errors.New("db: KeysSelect.Ints is not achievable when selecting more than 1 field")
-	}
-	var v []int
-	if err := ks.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (ks *KeysSelect) IntsX(ctx context.Context) []int {
-	v, err := ks.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a selector. It is only allowed when selecting one field.
-func (ks *KeysSelect) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = ks.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{keys.Label}
-	default:
-		err = fmt.Errorf("db: KeysSelect.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (ks *KeysSelect) IntX(ctx context.Context) int {
-	v, err := ks.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
-func (ks *KeysSelect) Float64s(ctx context.Context) ([]float64, error) {
-	if len(ks.fields) > 1 {
-		return nil, errors.New("db: KeysSelect.Float64s is not achievable when selecting more than 1 field")
-	}
-	var v []float64
-	if err := ks.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (ks *KeysSelect) Float64sX(ctx context.Context) []float64 {
-	v, err := ks.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
-func (ks *KeysSelect) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = ks.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{keys.Label}
-	default:
-		err = fmt.Errorf("db: KeysSelect.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (ks *KeysSelect) Float64X(ctx context.Context) float64 {
-	v, err := ks.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from a selector. It is only allowed when selecting one field.
-func (ks *KeysSelect) Bools(ctx context.Context) ([]bool, error) {
-	if len(ks.fields) > 1 {
-		return nil, errors.New("db: KeysSelect.Bools is not achievable when selecting more than 1 field")
-	}
-	var v []bool
-	if err := ks.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (ks *KeysSelect) BoolsX(ctx context.Context) []bool {
-	v, err := ks.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a selector. It is only allowed when selecting one field.
-func (ks *KeysSelect) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = ks.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{keys.Label}
-	default:
-		err = fmt.Errorf("db: KeysSelect.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (ks *KeysSelect) BoolX(ctx context.Context) bool {
-	v, err := ks.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (ks *KeysSelect) sqlScan(ctx context.Context, v interface{}) error {
 	rows := &sql.Rows{}
 	query, args := ks.sql.Query()
diff --git a/storage/ent/db/keys_update.go b/storage/ent/db/keys_update.go
index e5b5529a..b5fbefff 100644
--- a/storage/ent/db/keys_update.go
+++ b/storage/ent/db/keys_update.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -14,7 +14,7 @@ import (
 	"github.com/dexidp/dex/storage"
 	"github.com/dexidp/dex/storage/ent/db/keys"
 	"github.com/dexidp/dex/storage/ent/db/predicate"
-	"gopkg.in/square/go-jose.v2"
+	jose "gopkg.in/square/go-jose.v2"
 )
 
 // KeysUpdate is the builder for updating Keys entities.
@@ -163,7 +163,7 @@ func (ku *KeysUpdate) sqlSave(ctx context.Context) (n int, err error) {
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{keys.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return 0, err
 	}
@@ -239,9 +239,15 @@ func (kuo *KeysUpdateOne) Save(ctx context.Context) (*Keys, error) {
 			}
 			mut = kuo.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, kuo.mutation); err != nil {
+		v, err := mut.Mutate(ctx, kuo.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*Keys)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from KeysMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -338,7 +344,7 @@ func (kuo *KeysUpdateOne) sqlSave(ctx context.Context) (_node *Keys, err error)
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{keys.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
diff --git a/storage/ent/db/migrate/migrate.go b/storage/ent/db/migrate/migrate.go
index 9bdaf523..6bccf391 100644
--- a/storage/ent/db/migrate/migrate.go
+++ b/storage/ent/db/migrate/migrate.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package migrate
 
@@ -28,9 +28,6 @@ var (
 	// and therefore, it's recommended to enable this option to get more
 	// flexibility in the schema changes.
 	WithDropIndex = schema.WithDropIndex
-	// WithFixture sets the foreign-key renaming option to the migration when upgrading
-	// ent from v0.1.0 (issue-#285). Defaults to false.
-	WithFixture = schema.WithFixture
 	// WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true.
 	WithForeignKeys = schema.WithForeignKeys
 )
@@ -45,11 +42,16 @@ func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} }
 
 // Create creates all schema resources.
 func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error {
+	return Create(ctx, s, Tables, opts...)
+}
+
+// Create creates all table resources using the given schema driver.
+func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error {
 	migrate, err := schema.NewMigrate(s.drv, opts...)
 	if err != nil {
 		return fmt.Errorf("ent/migrate: %w", err)
 	}
-	return migrate.Create(ctx, Tables...)
+	return migrate.Create(ctx, tables...)
 }
 
 // WriteTo writes the schema changes to w instead of running them against the database.
@@ -59,13 +61,5 @@ func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error
 // 	}
 //
 func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error {
-	drv := &schema.WriteDriver{
-		Writer: w,
-		Driver: s.drv,
-	}
-	migrate, err := schema.NewMigrate(drv, opts...)
-	if err != nil {
-		return fmt.Errorf("ent/migrate: %w", err)
-	}
-	return migrate.Create(ctx, Tables...)
+	return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...)
 }
diff --git a/storage/ent/db/migrate/schema.go b/storage/ent/db/migrate/schema.go
index 0577e0df..d3295a0c 100644
--- a/storage/ent/db/migrate/schema.go
+++ b/storage/ent/db/migrate/schema.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package migrate
 
@@ -102,6 +102,8 @@ var (
 		{Name: "expiry", Type: field.TypeTime, SchemaType: map[string]string{"mysql": "datetime(3)", "postgres": "timestamptz", "sqlite3": "timestamp"}},
 		{Name: "last_request", Type: field.TypeTime, SchemaType: map[string]string{"mysql": "datetime(3)", "postgres": "timestamptz", "sqlite3": "timestamp"}},
 		{Name: "poll_interval", Type: field.TypeInt},
+		{Name: "code_challenge", Type: field.TypeString, Size: 2147483647, Default: "", SchemaType: map[string]string{"mysql": "varchar(384)", "postgres": "text", "sqlite3": "text"}},
+		{Name: "code_challenge_method", Type: field.TypeString, Size: 2147483647, Default: "", SchemaType: map[string]string{"mysql": "varchar(384)", "postgres": "text", "sqlite3": "text"}},
 	}
 	// DeviceTokensTable holds the schema information for the "device_tokens" table.
 	DeviceTokensTable = &schema.Table{
diff --git a/storage/ent/db/mutation.go b/storage/ent/db/mutation.go
index 5418fd15..85e1af72 100644
--- a/storage/ent/db/mutation.go
+++ b/storage/ent/db/mutation.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -21,7 +21,7 @@ import (
 	"github.com/dexidp/dex/storage/ent/db/password"
 	"github.com/dexidp/dex/storage/ent/db/predicate"
 	"github.com/dexidp/dex/storage/ent/db/refreshtoken"
-	"gopkg.in/square/go-jose.v2"
+	jose "gopkg.in/square/go-jose.v2"
 
 	"entgo.io/ent"
 )
@@ -3687,20 +3687,22 @@ func (m *DeviceRequestMutation) ResetEdge(name string) error {
 // DeviceTokenMutation represents an operation that mutates the DeviceToken nodes in the graph.
 type DeviceTokenMutation struct {
 	config
-	op               Op
-	typ              string
-	id               *int
-	device_code      *string
-	status           *string
-	token            *[]byte
-	expiry           *time.Time
-	last_request     *time.Time
-	poll_interval    *int
-	addpoll_interval *int
-	clearedFields    map[string]struct{}
-	done             bool
-	oldValue         func(context.Context) (*DeviceToken, error)
-	predicates       []predicate.DeviceToken
+	op                    Op
+	typ                   string
+	id                    *int
+	device_code           *string
+	status                *string
+	token                 *[]byte
+	expiry                *time.Time
+	last_request          *time.Time
+	poll_interval         *int
+	addpoll_interval      *int
+	code_challenge        *string
+	code_challenge_method *string
+	clearedFields         map[string]struct{}
+	done                  bool
+	oldValue              func(context.Context) (*DeviceToken, error)
+	predicates            []predicate.DeviceToken
 }
 
 var _ ent.Mutation = (*DeviceTokenMutation)(nil)
@@ -4050,6 +4052,78 @@ func (m *DeviceTokenMutation) ResetPollInterval() {
 	m.addpoll_interval = nil
 }
 
+// SetCodeChallenge sets the "code_challenge" field.
+func (m *DeviceTokenMutation) SetCodeChallenge(s string) {
+	m.code_challenge = &s
+}
+
+// CodeChallenge returns the value of the "code_challenge" field in the mutation.
+func (m *DeviceTokenMutation) CodeChallenge() (r string, exists bool) {
+	v := m.code_challenge
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldCodeChallenge returns the old "code_challenge" field's value of the DeviceToken entity.
+// If the DeviceToken object wasn't provided to the builder, the object is fetched from the database.
+// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
+func (m *DeviceTokenMutation) OldCodeChallenge(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldCodeChallenge is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldCodeChallenge requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldCodeChallenge: %w", err)
+	}
+	return oldValue.CodeChallenge, nil
+}
+
+// ResetCodeChallenge resets all changes to the "code_challenge" field.
+func (m *DeviceTokenMutation) ResetCodeChallenge() {
+	m.code_challenge = nil
+}
+
+// SetCodeChallengeMethod sets the "code_challenge_method" field.
+func (m *DeviceTokenMutation) SetCodeChallengeMethod(s string) {
+	m.code_challenge_method = &s
+}
+
+// CodeChallengeMethod returns the value of the "code_challenge_method" field in the mutation.
+func (m *DeviceTokenMutation) CodeChallengeMethod() (r string, exists bool) {
+	v := m.code_challenge_method
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldCodeChallengeMethod returns the old "code_challenge_method" field's value of the DeviceToken entity.
+// If the DeviceToken object wasn't provided to the builder, the object is fetched from the database.
+// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
+func (m *DeviceTokenMutation) OldCodeChallengeMethod(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldCodeChallengeMethod is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldCodeChallengeMethod requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldCodeChallengeMethod: %w", err)
+	}
+	return oldValue.CodeChallengeMethod, nil
+}
+
+// ResetCodeChallengeMethod resets all changes to the "code_challenge_method" field.
+func (m *DeviceTokenMutation) ResetCodeChallengeMethod() {
+	m.code_challenge_method = nil
+}
+
 // Where appends a list predicates to the DeviceTokenMutation builder.
 func (m *DeviceTokenMutation) Where(ps ...predicate.DeviceToken) {
 	m.predicates = append(m.predicates, ps...)
@@ -4069,7 +4143,7 @@ func (m *DeviceTokenMutation) Type() string {
 // order to get all numeric fields that were incremented/decremented, call
 // AddedFields().
 func (m *DeviceTokenMutation) Fields() []string {
-	fields := make([]string, 0, 6)
+	fields := make([]string, 0, 8)
 	if m.device_code != nil {
 		fields = append(fields, devicetoken.FieldDeviceCode)
 	}
@@ -4088,6 +4162,12 @@ func (m *DeviceTokenMutation) Fields() []string {
 	if m.poll_interval != nil {
 		fields = append(fields, devicetoken.FieldPollInterval)
 	}
+	if m.code_challenge != nil {
+		fields = append(fields, devicetoken.FieldCodeChallenge)
+	}
+	if m.code_challenge_method != nil {
+		fields = append(fields, devicetoken.FieldCodeChallengeMethod)
+	}
 	return fields
 }
 
@@ -4108,6 +4188,10 @@ func (m *DeviceTokenMutation) Field(name string) (ent.Value, bool) {
 		return m.LastRequest()
 	case devicetoken.FieldPollInterval:
 		return m.PollInterval()
+	case devicetoken.FieldCodeChallenge:
+		return m.CodeChallenge()
+	case devicetoken.FieldCodeChallengeMethod:
+		return m.CodeChallengeMethod()
 	}
 	return nil, false
 }
@@ -4129,6 +4213,10 @@ func (m *DeviceTokenMutation) OldField(ctx context.Context, name string) (ent.Va
 		return m.OldLastRequest(ctx)
 	case devicetoken.FieldPollInterval:
 		return m.OldPollInterval(ctx)
+	case devicetoken.FieldCodeChallenge:
+		return m.OldCodeChallenge(ctx)
+	case devicetoken.FieldCodeChallengeMethod:
+		return m.OldCodeChallengeMethod(ctx)
 	}
 	return nil, fmt.Errorf("unknown DeviceToken field %s", name)
 }
@@ -4180,6 +4268,20 @@ func (m *DeviceTokenMutation) SetField(name string, value ent.Value) error {
 		}
 		m.SetPollInterval(v)
 		return nil
+	case devicetoken.FieldCodeChallenge:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetCodeChallenge(v)
+		return nil
+	case devicetoken.FieldCodeChallengeMethod:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetCodeChallengeMethod(v)
+		return nil
 	}
 	return fmt.Errorf("unknown DeviceToken field %s", name)
 }
@@ -4271,6 +4373,12 @@ func (m *DeviceTokenMutation) ResetField(name string) error {
 	case devicetoken.FieldPollInterval:
 		m.ResetPollInterval()
 		return nil
+	case devicetoken.FieldCodeChallenge:
+		m.ResetCodeChallenge()
+		return nil
+	case devicetoken.FieldCodeChallengeMethod:
+		m.ResetCodeChallengeMethod()
+		return nil
 	}
 	return fmt.Errorf("unknown DeviceToken field %s", name)
 }
diff --git a/storage/ent/db/oauth2client.go b/storage/ent/db/oauth2client.go
index 57d64a49..f96ca218 100644
--- a/storage/ent/db/oauth2client.go
+++ b/storage/ent/db/oauth2client.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -117,11 +117,11 @@ func (o *OAuth2Client) Update() *OAuth2ClientUpdateOne {
 // Unwrap unwraps the OAuth2Client entity that was returned from a transaction after it was closed,
 // so that all future queries will be executed through the driver which created the transaction.
 func (o *OAuth2Client) Unwrap() *OAuth2Client {
-	tx, ok := o.config.driver.(*txDriver)
+	_tx, ok := o.config.driver.(*txDriver)
 	if !ok {
 		panic("db: OAuth2Client is not a transactional entity")
 	}
-	o.config.driver = tx.drv
+	o.config.driver = _tx.drv
 	return o
 }
 
@@ -129,18 +129,23 @@ func (o *OAuth2Client) Unwrap() *OAuth2Client {
 func (o *OAuth2Client) String() string {
 	var builder strings.Builder
 	builder.WriteString("OAuth2Client(")
-	builder.WriteString(fmt.Sprintf("id=%v", o.ID))
-	builder.WriteString(", secret=")
+	builder.WriteString(fmt.Sprintf("id=%v, ", o.ID))
+	builder.WriteString("secret=")
 	builder.WriteString(o.Secret)
-	builder.WriteString(", redirect_uris=")
+	builder.WriteString(", ")
+	builder.WriteString("redirect_uris=")
 	builder.WriteString(fmt.Sprintf("%v", o.RedirectUris))
-	builder.WriteString(", trusted_peers=")
+	builder.WriteString(", ")
+	builder.WriteString("trusted_peers=")
 	builder.WriteString(fmt.Sprintf("%v", o.TrustedPeers))
-	builder.WriteString(", public=")
+	builder.WriteString(", ")
+	builder.WriteString("public=")
 	builder.WriteString(fmt.Sprintf("%v", o.Public))
-	builder.WriteString(", name=")
+	builder.WriteString(", ")
+	builder.WriteString("name=")
 	builder.WriteString(o.Name)
-	builder.WriteString(", logo_url=")
+	builder.WriteString(", ")
+	builder.WriteString("logo_url=")
 	builder.WriteString(o.LogoURL)
 	builder.WriteByte(')')
 	return builder.String()
diff --git a/storage/ent/db/oauth2client/oauth2client.go b/storage/ent/db/oauth2client/oauth2client.go
index cbfdad1d..55b00c16 100644
--- a/storage/ent/db/oauth2client/oauth2client.go
+++ b/storage/ent/db/oauth2client/oauth2client.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package oauth2client
 
diff --git a/storage/ent/db/oauth2client/where.go b/storage/ent/db/oauth2client/where.go
index b7dbf7a1..d74a6ab7 100644
--- a/storage/ent/db/oauth2client/where.go
+++ b/storage/ent/db/oauth2client/where.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package oauth2client
 
@@ -31,12 +31,6 @@ func IDNEQ(id string) predicate.OAuth2Client {
 // IDIn applies the In predicate on the ID field.
 func IDIn(ids ...string) predicate.OAuth2Client {
 	return predicate.OAuth2Client(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -48,12 +42,6 @@ func IDIn(ids ...string) predicate.OAuth2Client {
 // IDNotIn applies the NotIn predicate on the ID field.
 func IDNotIn(ids ...string) predicate.OAuth2Client {
 	return predicate.OAuth2Client(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -139,12 +127,6 @@ func SecretIn(vs ...string) predicate.OAuth2Client {
 		v[i] = vs[i]
 	}
 	return predicate.OAuth2Client(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldSecret), v...))
 	})
 }
@@ -156,12 +138,6 @@ func SecretNotIn(vs ...string) predicate.OAuth2Client {
 		v[i] = vs[i]
 	}
 	return predicate.OAuth2Client(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldSecret), v...))
 	})
 }
@@ -292,12 +268,6 @@ func NameIn(vs ...string) predicate.OAuth2Client {
 		v[i] = vs[i]
 	}
 	return predicate.OAuth2Client(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldName), v...))
 	})
 }
@@ -309,12 +279,6 @@ func NameNotIn(vs ...string) predicate.OAuth2Client {
 		v[i] = vs[i]
 	}
 	return predicate.OAuth2Client(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldName), v...))
 	})
 }
@@ -403,12 +367,6 @@ func LogoURLIn(vs ...string) predicate.OAuth2Client {
 		v[i] = vs[i]
 	}
 	return predicate.OAuth2Client(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldLogoURL), v...))
 	})
 }
@@ -420,12 +378,6 @@ func LogoURLNotIn(vs ...string) predicate.OAuth2Client {
 		v[i] = vs[i]
 	}
 	return predicate.OAuth2Client(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldLogoURL), v...))
 	})
 }
diff --git a/storage/ent/db/oauth2client_create.go b/storage/ent/db/oauth2client_create.go
index 4c64b11b..02c41a83 100644
--- a/storage/ent/db/oauth2client_create.go
+++ b/storage/ent/db/oauth2client_create.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -100,9 +100,15 @@ func (oc *OAuth2ClientCreate) Save(ctx context.Context) (*OAuth2Client, error) {
 			}
 			mut = oc.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, oc.mutation); err != nil {
+		v, err := mut.Mutate(ctx, oc.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*OAuth2Client)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from OAuth2ClientMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -170,7 +176,7 @@ func (oc *OAuth2ClientCreate) sqlSave(ctx context.Context) (*OAuth2Client, error
 	_node, _spec := oc.createSpec()
 	if err := sqlgraph.CreateNode(ctx, oc.driver, _spec); err != nil {
 		if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
@@ -282,7 +288,7 @@ func (ocb *OAuth2ClientCreateBulk) Save(ctx context.Context) ([]*OAuth2Client, e
 					// Invoke the actual operation on the latest mutation in the chain.
 					if err = sqlgraph.BatchCreate(ctx, ocb.driver, spec); err != nil {
 						if sqlgraph.IsConstraintError(err) {
-							err = &ConstraintError{err.Error(), err}
+							err = &ConstraintError{msg: err.Error(), wrap: err}
 						}
 					}
 				}
diff --git a/storage/ent/db/oauth2client_delete.go b/storage/ent/db/oauth2client_delete.go
index 71a33c76..239d904d 100644
--- a/storage/ent/db/oauth2client_delete.go
+++ b/storage/ent/db/oauth2client_delete.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -84,7 +84,11 @@ func (od *OAuth2ClientDelete) sqlExec(ctx context.Context) (int, error) {
 			}
 		}
 	}
-	return sqlgraph.DeleteNodes(ctx, od.driver, _spec)
+	affected, err := sqlgraph.DeleteNodes(ctx, od.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	return affected, err
 }
 
 // OAuth2ClientDeleteOne is the builder for deleting a single OAuth2Client entity.
diff --git a/storage/ent/db/oauth2client_query.go b/storage/ent/db/oauth2client_query.go
index d66607ab..1776c943 100644
--- a/storage/ent/db/oauth2client_query.go
+++ b/storage/ent/db/oauth2client_query.go
@@ -1,10 +1,9 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"math"
 
@@ -264,15 +263,17 @@ func (oq *OAuth2ClientQuery) Clone() *OAuth2ClientQuery {
 //		Scan(ctx, &v)
 //
 func (oq *OAuth2ClientQuery) GroupBy(field string, fields ...string) *OAuth2ClientGroupBy {
-	group := &OAuth2ClientGroupBy{config: oq.config}
-	group.fields = append([]string{field}, fields...)
-	group.path = func(ctx context.Context) (prev *sql.Selector, err error) {
+	grbuild := &OAuth2ClientGroupBy{config: oq.config}
+	grbuild.fields = append([]string{field}, fields...)
+	grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
 		if err := oq.prepareQuery(ctx); err != nil {
 			return nil, err
 		}
 		return oq.sqlQuery(ctx), nil
 	}
-	return group
+	grbuild.label = oauth2client.Label
+	grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
+	return grbuild
 }
 
 // Select allows the selection one or more fields/columns for the given query,
@@ -290,7 +291,10 @@ func (oq *OAuth2ClientQuery) GroupBy(field string, fields ...string) *OAuth2Clie
 //
 func (oq *OAuth2ClientQuery) Select(fields ...string) *OAuth2ClientSelect {
 	oq.fields = append(oq.fields, fields...)
-	return &OAuth2ClientSelect{OAuth2ClientQuery: oq}
+	selbuild := &OAuth2ClientSelect{OAuth2ClientQuery: oq}
+	selbuild.label = oauth2client.Label
+	selbuild.flds, selbuild.scan = &oq.fields, selbuild.Scan
+	return selbuild
 }
 
 func (oq *OAuth2ClientQuery) prepareQuery(ctx context.Context) error {
@@ -309,23 +313,22 @@ func (oq *OAuth2ClientQuery) prepareQuery(ctx context.Context) error {
 	return nil
 }
 
-func (oq *OAuth2ClientQuery) sqlAll(ctx context.Context) ([]*OAuth2Client, error) {
+func (oq *OAuth2ClientQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*OAuth2Client, error) {
 	var (
 		nodes = []*OAuth2Client{}
 		_spec = oq.querySpec()
 	)
 	_spec.ScanValues = func(columns []string) ([]interface{}, error) {
-		node := &OAuth2Client{config: oq.config}
-		nodes = append(nodes, node)
-		return node.scanValues(columns)
+		return (*OAuth2Client).scanValues(nil, columns)
 	}
 	_spec.Assign = func(columns []string, values []interface{}) error {
-		if len(nodes) == 0 {
-			return fmt.Errorf("db: Assign called without calling ScanValues")
-		}
-		node := nodes[len(nodes)-1]
+		node := &OAuth2Client{config: oq.config}
+		nodes = append(nodes, node)
 		return node.assignValues(columns, values)
 	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
 	if err := sqlgraph.QueryNodes(ctx, oq.driver, _spec); err != nil {
 		return nil, err
 	}
@@ -435,6 +438,7 @@ func (oq *OAuth2ClientQuery) sqlQuery(ctx context.Context) *sql.Selector {
 // OAuth2ClientGroupBy is the group-by builder for OAuth2Client entities.
 type OAuth2ClientGroupBy struct {
 	config
+	selector
 	fields []string
 	fns    []AggregateFunc
 	// intermediate query (i.e. traversal path).
@@ -458,209 +462,6 @@ func (ogb *OAuth2ClientGroupBy) Scan(ctx context.Context, v interface{}) error {
 	return ogb.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (ogb *OAuth2ClientGroupBy) ScanX(ctx context.Context, v interface{}) {
-	if err := ogb.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (ogb *OAuth2ClientGroupBy) Strings(ctx context.Context) ([]string, error) {
-	if len(ogb.fields) > 1 {
-		return nil, errors.New("db: OAuth2ClientGroupBy.Strings is not achievable when grouping more than 1 field")
-	}
-	var v []string
-	if err := ogb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (ogb *OAuth2ClientGroupBy) StringsX(ctx context.Context) []string {
-	v, err := ogb.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (ogb *OAuth2ClientGroupBy) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = ogb.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{oauth2client.Label}
-	default:
-		err = fmt.Errorf("db: OAuth2ClientGroupBy.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (ogb *OAuth2ClientGroupBy) StringX(ctx context.Context) string {
-	v, err := ogb.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (ogb *OAuth2ClientGroupBy) Ints(ctx context.Context) ([]int, error) {
-	if len(ogb.fields) > 1 {
-		return nil, errors.New("db: OAuth2ClientGroupBy.Ints is not achievable when grouping more than 1 field")
-	}
-	var v []int
-	if err := ogb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (ogb *OAuth2ClientGroupBy) IntsX(ctx context.Context) []int {
-	v, err := ogb.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (ogb *OAuth2ClientGroupBy) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = ogb.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{oauth2client.Label}
-	default:
-		err = fmt.Errorf("db: OAuth2ClientGroupBy.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (ogb *OAuth2ClientGroupBy) IntX(ctx context.Context) int {
-	v, err := ogb.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (ogb *OAuth2ClientGroupBy) Float64s(ctx context.Context) ([]float64, error) {
-	if len(ogb.fields) > 1 {
-		return nil, errors.New("db: OAuth2ClientGroupBy.Float64s is not achievable when grouping more than 1 field")
-	}
-	var v []float64
-	if err := ogb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (ogb *OAuth2ClientGroupBy) Float64sX(ctx context.Context) []float64 {
-	v, err := ogb.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (ogb *OAuth2ClientGroupBy) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = ogb.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{oauth2client.Label}
-	default:
-		err = fmt.Errorf("db: OAuth2ClientGroupBy.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (ogb *OAuth2ClientGroupBy) Float64X(ctx context.Context) float64 {
-	v, err := ogb.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (ogb *OAuth2ClientGroupBy) Bools(ctx context.Context) ([]bool, error) {
-	if len(ogb.fields) > 1 {
-		return nil, errors.New("db: OAuth2ClientGroupBy.Bools is not achievable when grouping more than 1 field")
-	}
-	var v []bool
-	if err := ogb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (ogb *OAuth2ClientGroupBy) BoolsX(ctx context.Context) []bool {
-	v, err := ogb.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (ogb *OAuth2ClientGroupBy) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = ogb.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{oauth2client.Label}
-	default:
-		err = fmt.Errorf("db: OAuth2ClientGroupBy.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (ogb *OAuth2ClientGroupBy) BoolX(ctx context.Context) bool {
-	v, err := ogb.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (ogb *OAuth2ClientGroupBy) sqlScan(ctx context.Context, v interface{}) error {
 	for _, f := range ogb.fields {
 		if !oauth2client.ValidColumn(f) {
@@ -702,6 +503,7 @@ func (ogb *OAuth2ClientGroupBy) sqlQuery() *sql.Selector {
 // OAuth2ClientSelect is the builder for selecting fields of OAuth2Client entities.
 type OAuth2ClientSelect struct {
 	*OAuth2ClientQuery
+	selector
 	// intermediate query (i.e. traversal path).
 	sql *sql.Selector
 }
@@ -715,201 +517,6 @@ func (os *OAuth2ClientSelect) Scan(ctx context.Context, v interface{}) error {
 	return os.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (os *OAuth2ClientSelect) ScanX(ctx context.Context, v interface{}) {
-	if err := os.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from a selector. It is only allowed when selecting one field.
-func (os *OAuth2ClientSelect) Strings(ctx context.Context) ([]string, error) {
-	if len(os.fields) > 1 {
-		return nil, errors.New("db: OAuth2ClientSelect.Strings is not achievable when selecting more than 1 field")
-	}
-	var v []string
-	if err := os.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (os *OAuth2ClientSelect) StringsX(ctx context.Context) []string {
-	v, err := os.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a selector. It is only allowed when selecting one field.
-func (os *OAuth2ClientSelect) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = os.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{oauth2client.Label}
-	default:
-		err = fmt.Errorf("db: OAuth2ClientSelect.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (os *OAuth2ClientSelect) StringX(ctx context.Context) string {
-	v, err := os.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from a selector. It is only allowed when selecting one field.
-func (os *OAuth2ClientSelect) Ints(ctx context.Context) ([]int, error) {
-	if len(os.fields) > 1 {
-		return nil, errors.New("db: OAuth2ClientSelect.Ints is not achievable when selecting more than 1 field")
-	}
-	var v []int
-	if err := os.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (os *OAuth2ClientSelect) IntsX(ctx context.Context) []int {
-	v, err := os.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a selector. It is only allowed when selecting one field.
-func (os *OAuth2ClientSelect) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = os.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{oauth2client.Label}
-	default:
-		err = fmt.Errorf("db: OAuth2ClientSelect.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (os *OAuth2ClientSelect) IntX(ctx context.Context) int {
-	v, err := os.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
-func (os *OAuth2ClientSelect) Float64s(ctx context.Context) ([]float64, error) {
-	if len(os.fields) > 1 {
-		return nil, errors.New("db: OAuth2ClientSelect.Float64s is not achievable when selecting more than 1 field")
-	}
-	var v []float64
-	if err := os.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (os *OAuth2ClientSelect) Float64sX(ctx context.Context) []float64 {
-	v, err := os.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
-func (os *OAuth2ClientSelect) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = os.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{oauth2client.Label}
-	default:
-		err = fmt.Errorf("db: OAuth2ClientSelect.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (os *OAuth2ClientSelect) Float64X(ctx context.Context) float64 {
-	v, err := os.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from a selector. It is only allowed when selecting one field.
-func (os *OAuth2ClientSelect) Bools(ctx context.Context) ([]bool, error) {
-	if len(os.fields) > 1 {
-		return nil, errors.New("db: OAuth2ClientSelect.Bools is not achievable when selecting more than 1 field")
-	}
-	var v []bool
-	if err := os.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (os *OAuth2ClientSelect) BoolsX(ctx context.Context) []bool {
-	v, err := os.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a selector. It is only allowed when selecting one field.
-func (os *OAuth2ClientSelect) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = os.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{oauth2client.Label}
-	default:
-		err = fmt.Errorf("db: OAuth2ClientSelect.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (os *OAuth2ClientSelect) BoolX(ctx context.Context) bool {
-	v, err := os.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (os *OAuth2ClientSelect) sqlScan(ctx context.Context, v interface{}) error {
 	rows := &sql.Rows{}
 	query, args := os.sql.Query()
diff --git a/storage/ent/db/oauth2client_update.go b/storage/ent/db/oauth2client_update.go
index b86c5491..aeddbba6 100644
--- a/storage/ent/db/oauth2client_update.go
+++ b/storage/ent/db/oauth2client_update.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -236,7 +236,7 @@ func (ou *OAuth2ClientUpdate) sqlSave(ctx context.Context) (n int, err error) {
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{oauth2client.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return 0, err
 	}
@@ -342,9 +342,15 @@ func (ouo *OAuth2ClientUpdateOne) Save(ctx context.Context) (*OAuth2Client, erro
 			}
 			mut = ouo.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, ouo.mutation); err != nil {
+		v, err := mut.Mutate(ctx, ouo.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*OAuth2Client)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from OAuth2ClientMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -487,7 +493,7 @@ func (ouo *OAuth2ClientUpdateOne) sqlSave(ctx context.Context) (_node *OAuth2Cli
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{oauth2client.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
diff --git a/storage/ent/db/offlinesession.go b/storage/ent/db/offlinesession.go
index 6bfa5d2a..4b797e26 100644
--- a/storage/ent/db/offlinesession.go
+++ b/storage/ent/db/offlinesession.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -94,11 +94,11 @@ func (os *OfflineSession) Update() *OfflineSessionUpdateOne {
 // Unwrap unwraps the OfflineSession entity that was returned from a transaction after it was closed,
 // so that all future queries will be executed through the driver which created the transaction.
 func (os *OfflineSession) Unwrap() *OfflineSession {
-	tx, ok := os.config.driver.(*txDriver)
+	_tx, ok := os.config.driver.(*txDriver)
 	if !ok {
 		panic("db: OfflineSession is not a transactional entity")
 	}
-	os.config.driver = tx.drv
+	os.config.driver = _tx.drv
 	return os
 }
 
@@ -106,15 +106,18 @@ func (os *OfflineSession) Unwrap() *OfflineSession {
 func (os *OfflineSession) String() string {
 	var builder strings.Builder
 	builder.WriteString("OfflineSession(")
-	builder.WriteString(fmt.Sprintf("id=%v", os.ID))
-	builder.WriteString(", user_id=")
+	builder.WriteString(fmt.Sprintf("id=%v, ", os.ID))
+	builder.WriteString("user_id=")
 	builder.WriteString(os.UserID)
-	builder.WriteString(", conn_id=")
+	builder.WriteString(", ")
+	builder.WriteString("conn_id=")
 	builder.WriteString(os.ConnID)
-	builder.WriteString(", refresh=")
+	builder.WriteString(", ")
+	builder.WriteString("refresh=")
 	builder.WriteString(fmt.Sprintf("%v", os.Refresh))
+	builder.WriteString(", ")
 	if v := os.ConnectorData; v != nil {
-		builder.WriteString(", connector_data=")
+		builder.WriteString("connector_data=")
 		builder.WriteString(fmt.Sprintf("%v", *v))
 	}
 	builder.WriteByte(')')
diff --git a/storage/ent/db/offlinesession/offlinesession.go b/storage/ent/db/offlinesession/offlinesession.go
index df12c7f0..f996fe18 100644
--- a/storage/ent/db/offlinesession/offlinesession.go
+++ b/storage/ent/db/offlinesession/offlinesession.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package offlinesession
 
diff --git a/storage/ent/db/offlinesession/where.go b/storage/ent/db/offlinesession/where.go
index e24b9039..2dbab253 100644
--- a/storage/ent/db/offlinesession/where.go
+++ b/storage/ent/db/offlinesession/where.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package offlinesession
 
@@ -31,12 +31,6 @@ func IDNEQ(id string) predicate.OfflineSession {
 // IDIn applies the In predicate on the ID field.
 func IDIn(ids ...string) predicate.OfflineSession {
 	return predicate.OfflineSession(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -48,12 +42,6 @@ func IDIn(ids ...string) predicate.OfflineSession {
 // IDNotIn applies the NotIn predicate on the ID field.
 func IDNotIn(ids ...string) predicate.OfflineSession {
 	return predicate.OfflineSession(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -139,12 +127,6 @@ func UserIDIn(vs ...string) predicate.OfflineSession {
 		v[i] = vs[i]
 	}
 	return predicate.OfflineSession(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldUserID), v...))
 	})
 }
@@ -156,12 +138,6 @@ func UserIDNotIn(vs ...string) predicate.OfflineSession {
 		v[i] = vs[i]
 	}
 	return predicate.OfflineSession(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldUserID), v...))
 	})
 }
@@ -250,12 +226,6 @@ func ConnIDIn(vs ...string) predicate.OfflineSession {
 		v[i] = vs[i]
 	}
 	return predicate.OfflineSession(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldConnID), v...))
 	})
 }
@@ -267,12 +237,6 @@ func ConnIDNotIn(vs ...string) predicate.OfflineSession {
 		v[i] = vs[i]
 	}
 	return predicate.OfflineSession(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldConnID), v...))
 	})
 }
@@ -361,12 +325,6 @@ func RefreshIn(vs ...[]byte) predicate.OfflineSession {
 		v[i] = vs[i]
 	}
 	return predicate.OfflineSession(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldRefresh), v...))
 	})
 }
@@ -378,12 +336,6 @@ func RefreshNotIn(vs ...[]byte) predicate.OfflineSession {
 		v[i] = vs[i]
 	}
 	return predicate.OfflineSession(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldRefresh), v...))
 	})
 }
@@ -437,12 +389,6 @@ func ConnectorDataIn(vs ...[]byte) predicate.OfflineSession {
 		v[i] = vs[i]
 	}
 	return predicate.OfflineSession(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldConnectorData), v...))
 	})
 }
@@ -454,12 +400,6 @@ func ConnectorDataNotIn(vs ...[]byte) predicate.OfflineSession {
 		v[i] = vs[i]
 	}
 	return predicate.OfflineSession(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldConnectorData), v...))
 	})
 }
diff --git a/storage/ent/db/offlinesession_create.go b/storage/ent/db/offlinesession_create.go
index 74bb3213..82b8014f 100644
--- a/storage/ent/db/offlinesession_create.go
+++ b/storage/ent/db/offlinesession_create.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -88,9 +88,15 @@ func (osc *OfflineSessionCreate) Save(ctx context.Context) (*OfflineSession, err
 			}
 			mut = osc.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, osc.mutation); err != nil {
+		v, err := mut.Mutate(ctx, osc.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*OfflineSession)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from OfflineSessionMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -150,7 +156,7 @@ func (osc *OfflineSessionCreate) sqlSave(ctx context.Context) (*OfflineSession,
 	_node, _spec := osc.createSpec()
 	if err := sqlgraph.CreateNode(ctx, osc.driver, _spec); err != nil {
 		if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
@@ -246,7 +252,7 @@ func (oscb *OfflineSessionCreateBulk) Save(ctx context.Context) ([]*OfflineSessi
 					// Invoke the actual operation on the latest mutation in the chain.
 					if err = sqlgraph.BatchCreate(ctx, oscb.driver, spec); err != nil {
 						if sqlgraph.IsConstraintError(err) {
-							err = &ConstraintError{err.Error(), err}
+							err = &ConstraintError{msg: err.Error(), wrap: err}
 						}
 					}
 				}
diff --git a/storage/ent/db/offlinesession_delete.go b/storage/ent/db/offlinesession_delete.go
index 3b2e9143..b9c60ba9 100644
--- a/storage/ent/db/offlinesession_delete.go
+++ b/storage/ent/db/offlinesession_delete.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -84,7 +84,11 @@ func (osd *OfflineSessionDelete) sqlExec(ctx context.Context) (int, error) {
 			}
 		}
 	}
-	return sqlgraph.DeleteNodes(ctx, osd.driver, _spec)
+	affected, err := sqlgraph.DeleteNodes(ctx, osd.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	return affected, err
 }
 
 // OfflineSessionDeleteOne is the builder for deleting a single OfflineSession entity.
diff --git a/storage/ent/db/offlinesession_query.go b/storage/ent/db/offlinesession_query.go
index f40e2255..e5e09cf1 100644
--- a/storage/ent/db/offlinesession_query.go
+++ b/storage/ent/db/offlinesession_query.go
@@ -1,10 +1,9 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"math"
 
@@ -264,15 +263,17 @@ func (osq *OfflineSessionQuery) Clone() *OfflineSessionQuery {
 //		Scan(ctx, &v)
 //
 func (osq *OfflineSessionQuery) GroupBy(field string, fields ...string) *OfflineSessionGroupBy {
-	group := &OfflineSessionGroupBy{config: osq.config}
-	group.fields = append([]string{field}, fields...)
-	group.path = func(ctx context.Context) (prev *sql.Selector, err error) {
+	grbuild := &OfflineSessionGroupBy{config: osq.config}
+	grbuild.fields = append([]string{field}, fields...)
+	grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
 		if err := osq.prepareQuery(ctx); err != nil {
 			return nil, err
 		}
 		return osq.sqlQuery(ctx), nil
 	}
-	return group
+	grbuild.label = offlinesession.Label
+	grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
+	return grbuild
 }
 
 // Select allows the selection one or more fields/columns for the given query,
@@ -290,7 +291,10 @@ func (osq *OfflineSessionQuery) GroupBy(field string, fields ...string) *Offline
 //
 func (osq *OfflineSessionQuery) Select(fields ...string) *OfflineSessionSelect {
 	osq.fields = append(osq.fields, fields...)
-	return &OfflineSessionSelect{OfflineSessionQuery: osq}
+	selbuild := &OfflineSessionSelect{OfflineSessionQuery: osq}
+	selbuild.label = offlinesession.Label
+	selbuild.flds, selbuild.scan = &osq.fields, selbuild.Scan
+	return selbuild
 }
 
 func (osq *OfflineSessionQuery) prepareQuery(ctx context.Context) error {
@@ -309,23 +313,22 @@ func (osq *OfflineSessionQuery) prepareQuery(ctx context.Context) error {
 	return nil
 }
 
-func (osq *OfflineSessionQuery) sqlAll(ctx context.Context) ([]*OfflineSession, error) {
+func (osq *OfflineSessionQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*OfflineSession, error) {
 	var (
 		nodes = []*OfflineSession{}
 		_spec = osq.querySpec()
 	)
 	_spec.ScanValues = func(columns []string) ([]interface{}, error) {
-		node := &OfflineSession{config: osq.config}
-		nodes = append(nodes, node)
-		return node.scanValues(columns)
+		return (*OfflineSession).scanValues(nil, columns)
 	}
 	_spec.Assign = func(columns []string, values []interface{}) error {
-		if len(nodes) == 0 {
-			return fmt.Errorf("db: Assign called without calling ScanValues")
-		}
-		node := nodes[len(nodes)-1]
+		node := &OfflineSession{config: osq.config}
+		nodes = append(nodes, node)
 		return node.assignValues(columns, values)
 	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
 	if err := sqlgraph.QueryNodes(ctx, osq.driver, _spec); err != nil {
 		return nil, err
 	}
@@ -435,6 +438,7 @@ func (osq *OfflineSessionQuery) sqlQuery(ctx context.Context) *sql.Selector {
 // OfflineSessionGroupBy is the group-by builder for OfflineSession entities.
 type OfflineSessionGroupBy struct {
 	config
+	selector
 	fields []string
 	fns    []AggregateFunc
 	// intermediate query (i.e. traversal path).
@@ -458,209 +462,6 @@ func (osgb *OfflineSessionGroupBy) Scan(ctx context.Context, v interface{}) erro
 	return osgb.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (osgb *OfflineSessionGroupBy) ScanX(ctx context.Context, v interface{}) {
-	if err := osgb.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (osgb *OfflineSessionGroupBy) Strings(ctx context.Context) ([]string, error) {
-	if len(osgb.fields) > 1 {
-		return nil, errors.New("db: OfflineSessionGroupBy.Strings is not achievable when grouping more than 1 field")
-	}
-	var v []string
-	if err := osgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (osgb *OfflineSessionGroupBy) StringsX(ctx context.Context) []string {
-	v, err := osgb.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (osgb *OfflineSessionGroupBy) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = osgb.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{offlinesession.Label}
-	default:
-		err = fmt.Errorf("db: OfflineSessionGroupBy.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (osgb *OfflineSessionGroupBy) StringX(ctx context.Context) string {
-	v, err := osgb.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (osgb *OfflineSessionGroupBy) Ints(ctx context.Context) ([]int, error) {
-	if len(osgb.fields) > 1 {
-		return nil, errors.New("db: OfflineSessionGroupBy.Ints is not achievable when grouping more than 1 field")
-	}
-	var v []int
-	if err := osgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (osgb *OfflineSessionGroupBy) IntsX(ctx context.Context) []int {
-	v, err := osgb.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (osgb *OfflineSessionGroupBy) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = osgb.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{offlinesession.Label}
-	default:
-		err = fmt.Errorf("db: OfflineSessionGroupBy.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (osgb *OfflineSessionGroupBy) IntX(ctx context.Context) int {
-	v, err := osgb.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (osgb *OfflineSessionGroupBy) Float64s(ctx context.Context) ([]float64, error) {
-	if len(osgb.fields) > 1 {
-		return nil, errors.New("db: OfflineSessionGroupBy.Float64s is not achievable when grouping more than 1 field")
-	}
-	var v []float64
-	if err := osgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (osgb *OfflineSessionGroupBy) Float64sX(ctx context.Context) []float64 {
-	v, err := osgb.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (osgb *OfflineSessionGroupBy) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = osgb.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{offlinesession.Label}
-	default:
-		err = fmt.Errorf("db: OfflineSessionGroupBy.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (osgb *OfflineSessionGroupBy) Float64X(ctx context.Context) float64 {
-	v, err := osgb.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (osgb *OfflineSessionGroupBy) Bools(ctx context.Context) ([]bool, error) {
-	if len(osgb.fields) > 1 {
-		return nil, errors.New("db: OfflineSessionGroupBy.Bools is not achievable when grouping more than 1 field")
-	}
-	var v []bool
-	if err := osgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (osgb *OfflineSessionGroupBy) BoolsX(ctx context.Context) []bool {
-	v, err := osgb.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (osgb *OfflineSessionGroupBy) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = osgb.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{offlinesession.Label}
-	default:
-		err = fmt.Errorf("db: OfflineSessionGroupBy.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (osgb *OfflineSessionGroupBy) BoolX(ctx context.Context) bool {
-	v, err := osgb.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (osgb *OfflineSessionGroupBy) sqlScan(ctx context.Context, v interface{}) error {
 	for _, f := range osgb.fields {
 		if !offlinesession.ValidColumn(f) {
@@ -702,6 +503,7 @@ func (osgb *OfflineSessionGroupBy) sqlQuery() *sql.Selector {
 // OfflineSessionSelect is the builder for selecting fields of OfflineSession entities.
 type OfflineSessionSelect struct {
 	*OfflineSessionQuery
+	selector
 	// intermediate query (i.e. traversal path).
 	sql *sql.Selector
 }
@@ -715,201 +517,6 @@ func (oss *OfflineSessionSelect) Scan(ctx context.Context, v interface{}) error
 	return oss.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (oss *OfflineSessionSelect) ScanX(ctx context.Context, v interface{}) {
-	if err := oss.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from a selector. It is only allowed when selecting one field.
-func (oss *OfflineSessionSelect) Strings(ctx context.Context) ([]string, error) {
-	if len(oss.fields) > 1 {
-		return nil, errors.New("db: OfflineSessionSelect.Strings is not achievable when selecting more than 1 field")
-	}
-	var v []string
-	if err := oss.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (oss *OfflineSessionSelect) StringsX(ctx context.Context) []string {
-	v, err := oss.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a selector. It is only allowed when selecting one field.
-func (oss *OfflineSessionSelect) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = oss.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{offlinesession.Label}
-	default:
-		err = fmt.Errorf("db: OfflineSessionSelect.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (oss *OfflineSessionSelect) StringX(ctx context.Context) string {
-	v, err := oss.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from a selector. It is only allowed when selecting one field.
-func (oss *OfflineSessionSelect) Ints(ctx context.Context) ([]int, error) {
-	if len(oss.fields) > 1 {
-		return nil, errors.New("db: OfflineSessionSelect.Ints is not achievable when selecting more than 1 field")
-	}
-	var v []int
-	if err := oss.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (oss *OfflineSessionSelect) IntsX(ctx context.Context) []int {
-	v, err := oss.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a selector. It is only allowed when selecting one field.
-func (oss *OfflineSessionSelect) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = oss.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{offlinesession.Label}
-	default:
-		err = fmt.Errorf("db: OfflineSessionSelect.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (oss *OfflineSessionSelect) IntX(ctx context.Context) int {
-	v, err := oss.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
-func (oss *OfflineSessionSelect) Float64s(ctx context.Context) ([]float64, error) {
-	if len(oss.fields) > 1 {
-		return nil, errors.New("db: OfflineSessionSelect.Float64s is not achievable when selecting more than 1 field")
-	}
-	var v []float64
-	if err := oss.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (oss *OfflineSessionSelect) Float64sX(ctx context.Context) []float64 {
-	v, err := oss.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
-func (oss *OfflineSessionSelect) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = oss.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{offlinesession.Label}
-	default:
-		err = fmt.Errorf("db: OfflineSessionSelect.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (oss *OfflineSessionSelect) Float64X(ctx context.Context) float64 {
-	v, err := oss.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from a selector. It is only allowed when selecting one field.
-func (oss *OfflineSessionSelect) Bools(ctx context.Context) ([]bool, error) {
-	if len(oss.fields) > 1 {
-		return nil, errors.New("db: OfflineSessionSelect.Bools is not achievable when selecting more than 1 field")
-	}
-	var v []bool
-	if err := oss.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (oss *OfflineSessionSelect) BoolsX(ctx context.Context) []bool {
-	v, err := oss.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a selector. It is only allowed when selecting one field.
-func (oss *OfflineSessionSelect) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = oss.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{offlinesession.Label}
-	default:
-		err = fmt.Errorf("db: OfflineSessionSelect.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (oss *OfflineSessionSelect) BoolX(ctx context.Context) bool {
-	v, err := oss.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (oss *OfflineSessionSelect) sqlScan(ctx context.Context, v interface{}) error {
 	rows := &sql.Rows{}
 	query, args := oss.sql.Query()
diff --git a/storage/ent/db/offlinesession_update.go b/storage/ent/db/offlinesession_update.go
index e19f5a05..f9f1d9cb 100644
--- a/storage/ent/db/offlinesession_update.go
+++ b/storage/ent/db/offlinesession_update.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -193,7 +193,7 @@ func (osu *OfflineSessionUpdate) sqlSave(ctx context.Context) (n int, err error)
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{offlinesession.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return 0, err
 	}
@@ -281,9 +281,15 @@ func (osuo *OfflineSessionUpdateOne) Save(ctx context.Context) (*OfflineSession,
 			}
 			mut = osuo.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, osuo.mutation); err != nil {
+		v, err := mut.Mutate(ctx, osuo.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*OfflineSession)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from OfflineSessionMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -401,7 +407,7 @@ func (osuo *OfflineSessionUpdateOne) sqlSave(ctx context.Context) (_node *Offlin
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{offlinesession.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
diff --git a/storage/ent/db/password.go b/storage/ent/db/password.go
index 9a1043d6..cd30ec54 100644
--- a/storage/ent/db/password.go
+++ b/storage/ent/db/password.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -96,11 +96,11 @@ func (pa *Password) Update() *PasswordUpdateOne {
 // Unwrap unwraps the Password entity that was returned from a transaction after it was closed,
 // so that all future queries will be executed through the driver which created the transaction.
 func (pa *Password) Unwrap() *Password {
-	tx, ok := pa.config.driver.(*txDriver)
+	_tx, ok := pa.config.driver.(*txDriver)
 	if !ok {
 		panic("db: Password is not a transactional entity")
 	}
-	pa.config.driver = tx.drv
+	pa.config.driver = _tx.drv
 	return pa
 }
 
@@ -108,14 +108,17 @@ func (pa *Password) Unwrap() *Password {
 func (pa *Password) String() string {
 	var builder strings.Builder
 	builder.WriteString("Password(")
-	builder.WriteString(fmt.Sprintf("id=%v", pa.ID))
-	builder.WriteString(", email=")
+	builder.WriteString(fmt.Sprintf("id=%v, ", pa.ID))
+	builder.WriteString("email=")
 	builder.WriteString(pa.Email)
-	builder.WriteString(", hash=")
+	builder.WriteString(", ")
+	builder.WriteString("hash=")
 	builder.WriteString(fmt.Sprintf("%v", pa.Hash))
-	builder.WriteString(", username=")
+	builder.WriteString(", ")
+	builder.WriteString("username=")
 	builder.WriteString(pa.Username)
-	builder.WriteString(", user_id=")
+	builder.WriteString(", ")
+	builder.WriteString("user_id=")
 	builder.WriteString(pa.UserID)
 	builder.WriteByte(')')
 	return builder.String()
diff --git a/storage/ent/db/password/password.go b/storage/ent/db/password/password.go
index 52061b01..34fcac69 100644
--- a/storage/ent/db/password/password.go
+++ b/storage/ent/db/password/password.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package password
 
diff --git a/storage/ent/db/password/where.go b/storage/ent/db/password/where.go
index 979e9aa7..e33c134f 100644
--- a/storage/ent/db/password/where.go
+++ b/storage/ent/db/password/where.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package password
 
@@ -31,12 +31,6 @@ func IDNEQ(id int) predicate.Password {
 // IDIn applies the In predicate on the ID field.
 func IDIn(ids ...int) predicate.Password {
 	return predicate.Password(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -48,12 +42,6 @@ func IDIn(ids ...int) predicate.Password {
 // IDNotIn applies the NotIn predicate on the ID field.
 func IDNotIn(ids ...int) predicate.Password {
 	return predicate.Password(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -139,12 +127,6 @@ func EmailIn(vs ...string) predicate.Password {
 		v[i] = vs[i]
 	}
 	return predicate.Password(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldEmail), v...))
 	})
 }
@@ -156,12 +138,6 @@ func EmailNotIn(vs ...string) predicate.Password {
 		v[i] = vs[i]
 	}
 	return predicate.Password(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldEmail), v...))
 	})
 }
@@ -250,12 +226,6 @@ func HashIn(vs ...[]byte) predicate.Password {
 		v[i] = vs[i]
 	}
 	return predicate.Password(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldHash), v...))
 	})
 }
@@ -267,12 +237,6 @@ func HashNotIn(vs ...[]byte) predicate.Password {
 		v[i] = vs[i]
 	}
 	return predicate.Password(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldHash), v...))
 	})
 }
@@ -326,12 +290,6 @@ func UsernameIn(vs ...string) predicate.Password {
 		v[i] = vs[i]
 	}
 	return predicate.Password(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldUsername), v...))
 	})
 }
@@ -343,12 +301,6 @@ func UsernameNotIn(vs ...string) predicate.Password {
 		v[i] = vs[i]
 	}
 	return predicate.Password(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldUsername), v...))
 	})
 }
@@ -437,12 +389,6 @@ func UserIDIn(vs ...string) predicate.Password {
 		v[i] = vs[i]
 	}
 	return predicate.Password(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldUserID), v...))
 	})
 }
@@ -454,12 +400,6 @@ func UserIDNotIn(vs ...string) predicate.Password {
 		v[i] = vs[i]
 	}
 	return predicate.Password(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldUserID), v...))
 	})
 }
diff --git a/storage/ent/db/password_create.go b/storage/ent/db/password_create.go
index fa356dca..277a5c83 100644
--- a/storage/ent/db/password_create.go
+++ b/storage/ent/db/password_create.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -82,9 +82,15 @@ func (pc *PasswordCreate) Save(ctx context.Context) (*Password, error) {
 			}
 			mut = pc.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, pc.mutation); err != nil {
+		v, err := mut.Mutate(ctx, pc.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*Password)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from PasswordMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -147,7 +153,7 @@ func (pc *PasswordCreate) sqlSave(ctx context.Context) (*Password, error) {
 	_node, _spec := pc.createSpec()
 	if err := sqlgraph.CreateNode(ctx, pc.driver, _spec); err != nil {
 		if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
@@ -234,7 +240,7 @@ func (pcb *PasswordCreateBulk) Save(ctx context.Context) ([]*Password, error) {
 					// Invoke the actual operation on the latest mutation in the chain.
 					if err = sqlgraph.BatchCreate(ctx, pcb.driver, spec); err != nil {
 						if sqlgraph.IsConstraintError(err) {
-							err = &ConstraintError{err.Error(), err}
+							err = &ConstraintError{msg: err.Error(), wrap: err}
 						}
 					}
 				}
@@ -242,11 +248,11 @@ func (pcb *PasswordCreateBulk) Save(ctx context.Context) ([]*Password, error) {
 					return nil, err
 				}
 				mutation.id = &nodes[i].ID
-				mutation.done = true
 				if specs[i].ID.Value != nil {
 					id := specs[i].ID.Value.(int64)
 					nodes[i].ID = int(id)
 				}
+				mutation.done = true
 				return nodes[i], nil
 			})
 			for i := len(builder.hooks) - 1; i >= 0; i-- {
diff --git a/storage/ent/db/password_delete.go b/storage/ent/db/password_delete.go
index d1c59870..6bbe5af5 100644
--- a/storage/ent/db/password_delete.go
+++ b/storage/ent/db/password_delete.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -84,7 +84,11 @@ func (pd *PasswordDelete) sqlExec(ctx context.Context) (int, error) {
 			}
 		}
 	}
-	return sqlgraph.DeleteNodes(ctx, pd.driver, _spec)
+	affected, err := sqlgraph.DeleteNodes(ctx, pd.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	return affected, err
 }
 
 // PasswordDeleteOne is the builder for deleting a single Password entity.
diff --git a/storage/ent/db/password_query.go b/storage/ent/db/password_query.go
index 99b1af76..0da4d08a 100644
--- a/storage/ent/db/password_query.go
+++ b/storage/ent/db/password_query.go
@@ -1,10 +1,9 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"math"
 
@@ -264,15 +263,17 @@ func (pq *PasswordQuery) Clone() *PasswordQuery {
 //		Scan(ctx, &v)
 //
 func (pq *PasswordQuery) GroupBy(field string, fields ...string) *PasswordGroupBy {
-	group := &PasswordGroupBy{config: pq.config}
-	group.fields = append([]string{field}, fields...)
-	group.path = func(ctx context.Context) (prev *sql.Selector, err error) {
+	grbuild := &PasswordGroupBy{config: pq.config}
+	grbuild.fields = append([]string{field}, fields...)
+	grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
 		if err := pq.prepareQuery(ctx); err != nil {
 			return nil, err
 		}
 		return pq.sqlQuery(ctx), nil
 	}
-	return group
+	grbuild.label = password.Label
+	grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
+	return grbuild
 }
 
 // Select allows the selection one or more fields/columns for the given query,
@@ -290,7 +291,10 @@ func (pq *PasswordQuery) GroupBy(field string, fields ...string) *PasswordGroupB
 //
 func (pq *PasswordQuery) Select(fields ...string) *PasswordSelect {
 	pq.fields = append(pq.fields, fields...)
-	return &PasswordSelect{PasswordQuery: pq}
+	selbuild := &PasswordSelect{PasswordQuery: pq}
+	selbuild.label = password.Label
+	selbuild.flds, selbuild.scan = &pq.fields, selbuild.Scan
+	return selbuild
 }
 
 func (pq *PasswordQuery) prepareQuery(ctx context.Context) error {
@@ -309,23 +313,22 @@ func (pq *PasswordQuery) prepareQuery(ctx context.Context) error {
 	return nil
 }
 
-func (pq *PasswordQuery) sqlAll(ctx context.Context) ([]*Password, error) {
+func (pq *PasswordQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Password, error) {
 	var (
 		nodes = []*Password{}
 		_spec = pq.querySpec()
 	)
 	_spec.ScanValues = func(columns []string) ([]interface{}, error) {
-		node := &Password{config: pq.config}
-		nodes = append(nodes, node)
-		return node.scanValues(columns)
+		return (*Password).scanValues(nil, columns)
 	}
 	_spec.Assign = func(columns []string, values []interface{}) error {
-		if len(nodes) == 0 {
-			return fmt.Errorf("db: Assign called without calling ScanValues")
-		}
-		node := nodes[len(nodes)-1]
+		node := &Password{config: pq.config}
+		nodes = append(nodes, node)
 		return node.assignValues(columns, values)
 	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
 	if err := sqlgraph.QueryNodes(ctx, pq.driver, _spec); err != nil {
 		return nil, err
 	}
@@ -435,6 +438,7 @@ func (pq *PasswordQuery) sqlQuery(ctx context.Context) *sql.Selector {
 // PasswordGroupBy is the group-by builder for Password entities.
 type PasswordGroupBy struct {
 	config
+	selector
 	fields []string
 	fns    []AggregateFunc
 	// intermediate query (i.e. traversal path).
@@ -458,209 +462,6 @@ func (pgb *PasswordGroupBy) Scan(ctx context.Context, v interface{}) error {
 	return pgb.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (pgb *PasswordGroupBy) ScanX(ctx context.Context, v interface{}) {
-	if err := pgb.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (pgb *PasswordGroupBy) Strings(ctx context.Context) ([]string, error) {
-	if len(pgb.fields) > 1 {
-		return nil, errors.New("db: PasswordGroupBy.Strings is not achievable when grouping more than 1 field")
-	}
-	var v []string
-	if err := pgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (pgb *PasswordGroupBy) StringsX(ctx context.Context) []string {
-	v, err := pgb.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (pgb *PasswordGroupBy) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = pgb.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{password.Label}
-	default:
-		err = fmt.Errorf("db: PasswordGroupBy.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (pgb *PasswordGroupBy) StringX(ctx context.Context) string {
-	v, err := pgb.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (pgb *PasswordGroupBy) Ints(ctx context.Context) ([]int, error) {
-	if len(pgb.fields) > 1 {
-		return nil, errors.New("db: PasswordGroupBy.Ints is not achievable when grouping more than 1 field")
-	}
-	var v []int
-	if err := pgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (pgb *PasswordGroupBy) IntsX(ctx context.Context) []int {
-	v, err := pgb.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (pgb *PasswordGroupBy) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = pgb.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{password.Label}
-	default:
-		err = fmt.Errorf("db: PasswordGroupBy.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (pgb *PasswordGroupBy) IntX(ctx context.Context) int {
-	v, err := pgb.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (pgb *PasswordGroupBy) Float64s(ctx context.Context) ([]float64, error) {
-	if len(pgb.fields) > 1 {
-		return nil, errors.New("db: PasswordGroupBy.Float64s is not achievable when grouping more than 1 field")
-	}
-	var v []float64
-	if err := pgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (pgb *PasswordGroupBy) Float64sX(ctx context.Context) []float64 {
-	v, err := pgb.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (pgb *PasswordGroupBy) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = pgb.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{password.Label}
-	default:
-		err = fmt.Errorf("db: PasswordGroupBy.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (pgb *PasswordGroupBy) Float64X(ctx context.Context) float64 {
-	v, err := pgb.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (pgb *PasswordGroupBy) Bools(ctx context.Context) ([]bool, error) {
-	if len(pgb.fields) > 1 {
-		return nil, errors.New("db: PasswordGroupBy.Bools is not achievable when grouping more than 1 field")
-	}
-	var v []bool
-	if err := pgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (pgb *PasswordGroupBy) BoolsX(ctx context.Context) []bool {
-	v, err := pgb.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (pgb *PasswordGroupBy) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = pgb.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{password.Label}
-	default:
-		err = fmt.Errorf("db: PasswordGroupBy.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (pgb *PasswordGroupBy) BoolX(ctx context.Context) bool {
-	v, err := pgb.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (pgb *PasswordGroupBy) sqlScan(ctx context.Context, v interface{}) error {
 	for _, f := range pgb.fields {
 		if !password.ValidColumn(f) {
@@ -702,6 +503,7 @@ func (pgb *PasswordGroupBy) sqlQuery() *sql.Selector {
 // PasswordSelect is the builder for selecting fields of Password entities.
 type PasswordSelect struct {
 	*PasswordQuery
+	selector
 	// intermediate query (i.e. traversal path).
 	sql *sql.Selector
 }
@@ -715,201 +517,6 @@ func (ps *PasswordSelect) Scan(ctx context.Context, v interface{}) error {
 	return ps.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (ps *PasswordSelect) ScanX(ctx context.Context, v interface{}) {
-	if err := ps.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from a selector. It is only allowed when selecting one field.
-func (ps *PasswordSelect) Strings(ctx context.Context) ([]string, error) {
-	if len(ps.fields) > 1 {
-		return nil, errors.New("db: PasswordSelect.Strings is not achievable when selecting more than 1 field")
-	}
-	var v []string
-	if err := ps.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (ps *PasswordSelect) StringsX(ctx context.Context) []string {
-	v, err := ps.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a selector. It is only allowed when selecting one field.
-func (ps *PasswordSelect) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = ps.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{password.Label}
-	default:
-		err = fmt.Errorf("db: PasswordSelect.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (ps *PasswordSelect) StringX(ctx context.Context) string {
-	v, err := ps.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from a selector. It is only allowed when selecting one field.
-func (ps *PasswordSelect) Ints(ctx context.Context) ([]int, error) {
-	if len(ps.fields) > 1 {
-		return nil, errors.New("db: PasswordSelect.Ints is not achievable when selecting more than 1 field")
-	}
-	var v []int
-	if err := ps.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (ps *PasswordSelect) IntsX(ctx context.Context) []int {
-	v, err := ps.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a selector. It is only allowed when selecting one field.
-func (ps *PasswordSelect) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = ps.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{password.Label}
-	default:
-		err = fmt.Errorf("db: PasswordSelect.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (ps *PasswordSelect) IntX(ctx context.Context) int {
-	v, err := ps.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
-func (ps *PasswordSelect) Float64s(ctx context.Context) ([]float64, error) {
-	if len(ps.fields) > 1 {
-		return nil, errors.New("db: PasswordSelect.Float64s is not achievable when selecting more than 1 field")
-	}
-	var v []float64
-	if err := ps.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (ps *PasswordSelect) Float64sX(ctx context.Context) []float64 {
-	v, err := ps.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
-func (ps *PasswordSelect) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = ps.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{password.Label}
-	default:
-		err = fmt.Errorf("db: PasswordSelect.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (ps *PasswordSelect) Float64X(ctx context.Context) float64 {
-	v, err := ps.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from a selector. It is only allowed when selecting one field.
-func (ps *PasswordSelect) Bools(ctx context.Context) ([]bool, error) {
-	if len(ps.fields) > 1 {
-		return nil, errors.New("db: PasswordSelect.Bools is not achievable when selecting more than 1 field")
-	}
-	var v []bool
-	if err := ps.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (ps *PasswordSelect) BoolsX(ctx context.Context) []bool {
-	v, err := ps.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a selector. It is only allowed when selecting one field.
-func (ps *PasswordSelect) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = ps.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{password.Label}
-	default:
-		err = fmt.Errorf("db: PasswordSelect.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (ps *PasswordSelect) BoolX(ctx context.Context) bool {
-	v, err := ps.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (ps *PasswordSelect) sqlScan(ctx context.Context, v interface{}) error {
 	rows := &sql.Rows{}
 	query, args := ps.sql.Query()
diff --git a/storage/ent/db/password_update.go b/storage/ent/db/password_update.go
index f1c376af..8d149991 100644
--- a/storage/ent/db/password_update.go
+++ b/storage/ent/db/password_update.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -186,7 +186,7 @@ func (pu *PasswordUpdate) sqlSave(ctx context.Context) (n int, err error) {
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{password.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return 0, err
 	}
@@ -268,9 +268,15 @@ func (puo *PasswordUpdateOne) Save(ctx context.Context) (*Password, error) {
 			}
 			mut = puo.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, puo.mutation); err != nil {
+		v, err := mut.Mutate(ctx, puo.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*Password)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from PasswordMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -387,7 +393,7 @@ func (puo *PasswordUpdateOne) sqlSave(ctx context.Context) (_node *Password, err
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{password.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
diff --git a/storage/ent/db/predicate/predicate.go b/storage/ent/db/predicate/predicate.go
index 68270087..ed07a071 100644
--- a/storage/ent/db/predicate/predicate.go
+++ b/storage/ent/db/predicate/predicate.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package predicate
 
diff --git a/storage/ent/db/refreshtoken.go b/storage/ent/db/refreshtoken.go
index 3c591206..b5c75bb1 100644
--- a/storage/ent/db/refreshtoken.go
+++ b/storage/ent/db/refreshtoken.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -192,11 +192,11 @@ func (rt *RefreshToken) Update() *RefreshTokenUpdateOne {
 // Unwrap unwraps the RefreshToken entity that was returned from a transaction after it was closed,
 // so that all future queries will be executed through the driver which created the transaction.
 func (rt *RefreshToken) Unwrap() *RefreshToken {
-	tx, ok := rt.config.driver.(*txDriver)
+	_tx, ok := rt.config.driver.(*txDriver)
 	if !ok {
 		panic("db: RefreshToken is not a transactional entity")
 	}
-	rt.config.driver = tx.drv
+	rt.config.driver = _tx.drv
 	return rt
 }
 
@@ -204,38 +204,52 @@ func (rt *RefreshToken) Unwrap() *RefreshToken {
 func (rt *RefreshToken) String() string {
 	var builder strings.Builder
 	builder.WriteString("RefreshToken(")
-	builder.WriteString(fmt.Sprintf("id=%v", rt.ID))
-	builder.WriteString(", client_id=")
+	builder.WriteString(fmt.Sprintf("id=%v, ", rt.ID))
+	builder.WriteString("client_id=")
 	builder.WriteString(rt.ClientID)
-	builder.WriteString(", scopes=")
+	builder.WriteString(", ")
+	builder.WriteString("scopes=")
 	builder.WriteString(fmt.Sprintf("%v", rt.Scopes))
-	builder.WriteString(", nonce=")
+	builder.WriteString(", ")
+	builder.WriteString("nonce=")
 	builder.WriteString(rt.Nonce)
-	builder.WriteString(", claims_user_id=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_user_id=")
 	builder.WriteString(rt.ClaimsUserID)
-	builder.WriteString(", claims_username=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_username=")
 	builder.WriteString(rt.ClaimsUsername)
-	builder.WriteString(", claims_email=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_email=")
 	builder.WriteString(rt.ClaimsEmail)
-	builder.WriteString(", claims_email_verified=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_email_verified=")
 	builder.WriteString(fmt.Sprintf("%v", rt.ClaimsEmailVerified))
-	builder.WriteString(", claims_groups=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_groups=")
 	builder.WriteString(fmt.Sprintf("%v", rt.ClaimsGroups))
-	builder.WriteString(", claims_preferred_username=")
+	builder.WriteString(", ")
+	builder.WriteString("claims_preferred_username=")
 	builder.WriteString(rt.ClaimsPreferredUsername)
-	builder.WriteString(", connector_id=")
+	builder.WriteString(", ")
+	builder.WriteString("connector_id=")
 	builder.WriteString(rt.ConnectorID)
+	builder.WriteString(", ")
 	if v := rt.ConnectorData; v != nil {
-		builder.WriteString(", connector_data=")
+		builder.WriteString("connector_data=")
 		builder.WriteString(fmt.Sprintf("%v", *v))
 	}
-	builder.WriteString(", token=")
+	builder.WriteString(", ")
+	builder.WriteString("token=")
 	builder.WriteString(rt.Token)
-	builder.WriteString(", obsolete_token=")
+	builder.WriteString(", ")
+	builder.WriteString("obsolete_token=")
 	builder.WriteString(rt.ObsoleteToken)
-	builder.WriteString(", created_at=")
+	builder.WriteString(", ")
+	builder.WriteString("created_at=")
 	builder.WriteString(rt.CreatedAt.Format(time.ANSIC))
-	builder.WriteString(", last_used=")
+	builder.WriteString(", ")
+	builder.WriteString("last_used=")
 	builder.WriteString(rt.LastUsed.Format(time.ANSIC))
 	builder.WriteByte(')')
 	return builder.String()
diff --git a/storage/ent/db/refreshtoken/refreshtoken.go b/storage/ent/db/refreshtoken/refreshtoken.go
index 38efcc22..d11d8407 100644
--- a/storage/ent/db/refreshtoken/refreshtoken.go
+++ b/storage/ent/db/refreshtoken/refreshtoken.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package refreshtoken
 
diff --git a/storage/ent/db/refreshtoken/where.go b/storage/ent/db/refreshtoken/where.go
index 43a46093..e6abf982 100644
--- a/storage/ent/db/refreshtoken/where.go
+++ b/storage/ent/db/refreshtoken/where.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package refreshtoken
 
@@ -33,12 +33,6 @@ func IDNEQ(id string) predicate.RefreshToken {
 // IDIn applies the In predicate on the ID field.
 func IDIn(ids ...string) predicate.RefreshToken {
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -50,12 +44,6 @@ func IDIn(ids ...string) predicate.RefreshToken {
 // IDNotIn applies the NotIn predicate on the ID field.
 func IDNotIn(ids ...string) predicate.RefreshToken {
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(ids) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		v := make([]interface{}, len(ids))
 		for i := range v {
 			v[i] = ids[i]
@@ -204,12 +192,6 @@ func ClientIDIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClientID), v...))
 	})
 }
@@ -221,12 +203,6 @@ func ClientIDNotIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClientID), v...))
 	})
 }
@@ -329,12 +305,6 @@ func NonceIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldNonce), v...))
 	})
 }
@@ -346,12 +316,6 @@ func NonceNotIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldNonce), v...))
 	})
 }
@@ -440,12 +404,6 @@ func ClaimsUserIDIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClaimsUserID), v...))
 	})
 }
@@ -457,12 +415,6 @@ func ClaimsUserIDNotIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClaimsUserID), v...))
 	})
 }
@@ -551,12 +503,6 @@ func ClaimsUsernameIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClaimsUsername), v...))
 	})
 }
@@ -568,12 +514,6 @@ func ClaimsUsernameNotIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClaimsUsername), v...))
 	})
 }
@@ -662,12 +602,6 @@ func ClaimsEmailIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClaimsEmail), v...))
 	})
 }
@@ -679,12 +613,6 @@ func ClaimsEmailNotIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClaimsEmail), v...))
 	})
 }
@@ -801,12 +729,6 @@ func ClaimsPreferredUsernameIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldClaimsPreferredUsername), v...))
 	})
 }
@@ -818,12 +740,6 @@ func ClaimsPreferredUsernameNotIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldClaimsPreferredUsername), v...))
 	})
 }
@@ -912,12 +828,6 @@ func ConnectorIDIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldConnectorID), v...))
 	})
 }
@@ -929,12 +839,6 @@ func ConnectorIDNotIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldConnectorID), v...))
 	})
 }
@@ -1023,12 +927,6 @@ func ConnectorDataIn(vs ...[]byte) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldConnectorData), v...))
 	})
 }
@@ -1040,12 +938,6 @@ func ConnectorDataNotIn(vs ...[]byte) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldConnectorData), v...))
 	})
 }
@@ -1113,12 +1005,6 @@ func TokenIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldToken), v...))
 	})
 }
@@ -1130,12 +1016,6 @@ func TokenNotIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldToken), v...))
 	})
 }
@@ -1224,12 +1104,6 @@ func ObsoleteTokenIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldObsoleteToken), v...))
 	})
 }
@@ -1241,12 +1115,6 @@ func ObsoleteTokenNotIn(vs ...string) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldObsoleteToken), v...))
 	})
 }
@@ -1335,12 +1203,6 @@ func CreatedAtIn(vs ...time.Time) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldCreatedAt), v...))
 	})
 }
@@ -1352,12 +1214,6 @@ func CreatedAtNotIn(vs ...time.Time) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldCreatedAt), v...))
 	})
 }
@@ -1411,12 +1267,6 @@ func LastUsedIn(vs ...time.Time) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.In(s.C(FieldLastUsed), v...))
 	})
 }
@@ -1428,12 +1278,6 @@ func LastUsedNotIn(vs ...time.Time) predicate.RefreshToken {
 		v[i] = vs[i]
 	}
 	return predicate.RefreshToken(func(s *sql.Selector) {
-		// if not arguments were provided, append the FALSE constants,
-		// since we can't apply "IN ()". This will make this predicate falsy.
-		if len(v) == 0 {
-			s.Where(sql.False())
-			return
-		}
 		s.Where(sql.NotIn(s.C(FieldLastUsed), v...))
 	})
 }
diff --git a/storage/ent/db/refreshtoken_create.go b/storage/ent/db/refreshtoken_create.go
index 7e925f37..e2bd6c2f 100644
--- a/storage/ent/db/refreshtoken_create.go
+++ b/storage/ent/db/refreshtoken_create.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -196,9 +196,15 @@ func (rtc *RefreshTokenCreate) Save(ctx context.Context) (*RefreshToken, error)
 			}
 			mut = rtc.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, rtc.mutation); err != nil {
+		v, err := mut.Mutate(ctx, rtc.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*RefreshToken)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from RefreshTokenMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -329,7 +335,7 @@ func (rtc *RefreshTokenCreate) sqlSave(ctx context.Context) (*RefreshToken, erro
 	_node, _spec := rtc.createSpec()
 	if err := sqlgraph.CreateNode(ctx, rtc.driver, _spec); err != nil {
 		if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
@@ -514,7 +520,7 @@ func (rtcb *RefreshTokenCreateBulk) Save(ctx context.Context) ([]*RefreshToken,
 					// Invoke the actual operation on the latest mutation in the chain.
 					if err = sqlgraph.BatchCreate(ctx, rtcb.driver, spec); err != nil {
 						if sqlgraph.IsConstraintError(err) {
-							err = &ConstraintError{err.Error(), err}
+							err = &ConstraintError{msg: err.Error(), wrap: err}
 						}
 					}
 				}
diff --git a/storage/ent/db/refreshtoken_delete.go b/storage/ent/db/refreshtoken_delete.go
index e5c882bb..2c8d7c1e 100644
--- a/storage/ent/db/refreshtoken_delete.go
+++ b/storage/ent/db/refreshtoken_delete.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -84,7 +84,11 @@ func (rtd *RefreshTokenDelete) sqlExec(ctx context.Context) (int, error) {
 			}
 		}
 	}
-	return sqlgraph.DeleteNodes(ctx, rtd.driver, _spec)
+	affected, err := sqlgraph.DeleteNodes(ctx, rtd.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	return affected, err
 }
 
 // RefreshTokenDeleteOne is the builder for deleting a single RefreshToken entity.
diff --git a/storage/ent/db/refreshtoken_query.go b/storage/ent/db/refreshtoken_query.go
index d585fdc1..a90ac2f9 100644
--- a/storage/ent/db/refreshtoken_query.go
+++ b/storage/ent/db/refreshtoken_query.go
@@ -1,10 +1,9 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"math"
 
@@ -264,15 +263,17 @@ func (rtq *RefreshTokenQuery) Clone() *RefreshTokenQuery {
 //		Scan(ctx, &v)
 //
 func (rtq *RefreshTokenQuery) GroupBy(field string, fields ...string) *RefreshTokenGroupBy {
-	group := &RefreshTokenGroupBy{config: rtq.config}
-	group.fields = append([]string{field}, fields...)
-	group.path = func(ctx context.Context) (prev *sql.Selector, err error) {
+	grbuild := &RefreshTokenGroupBy{config: rtq.config}
+	grbuild.fields = append([]string{field}, fields...)
+	grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
 		if err := rtq.prepareQuery(ctx); err != nil {
 			return nil, err
 		}
 		return rtq.sqlQuery(ctx), nil
 	}
-	return group
+	grbuild.label = refreshtoken.Label
+	grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
+	return grbuild
 }
 
 // Select allows the selection one or more fields/columns for the given query,
@@ -290,7 +291,10 @@ func (rtq *RefreshTokenQuery) GroupBy(field string, fields ...string) *RefreshTo
 //
 func (rtq *RefreshTokenQuery) Select(fields ...string) *RefreshTokenSelect {
 	rtq.fields = append(rtq.fields, fields...)
-	return &RefreshTokenSelect{RefreshTokenQuery: rtq}
+	selbuild := &RefreshTokenSelect{RefreshTokenQuery: rtq}
+	selbuild.label = refreshtoken.Label
+	selbuild.flds, selbuild.scan = &rtq.fields, selbuild.Scan
+	return selbuild
 }
 
 func (rtq *RefreshTokenQuery) prepareQuery(ctx context.Context) error {
@@ -309,23 +313,22 @@ func (rtq *RefreshTokenQuery) prepareQuery(ctx context.Context) error {
 	return nil
 }
 
-func (rtq *RefreshTokenQuery) sqlAll(ctx context.Context) ([]*RefreshToken, error) {
+func (rtq *RefreshTokenQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*RefreshToken, error) {
 	var (
 		nodes = []*RefreshToken{}
 		_spec = rtq.querySpec()
 	)
 	_spec.ScanValues = func(columns []string) ([]interface{}, error) {
-		node := &RefreshToken{config: rtq.config}
-		nodes = append(nodes, node)
-		return node.scanValues(columns)
+		return (*RefreshToken).scanValues(nil, columns)
 	}
 	_spec.Assign = func(columns []string, values []interface{}) error {
-		if len(nodes) == 0 {
-			return fmt.Errorf("db: Assign called without calling ScanValues")
-		}
-		node := nodes[len(nodes)-1]
+		node := &RefreshToken{config: rtq.config}
+		nodes = append(nodes, node)
 		return node.assignValues(columns, values)
 	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
 	if err := sqlgraph.QueryNodes(ctx, rtq.driver, _spec); err != nil {
 		return nil, err
 	}
@@ -435,6 +438,7 @@ func (rtq *RefreshTokenQuery) sqlQuery(ctx context.Context) *sql.Selector {
 // RefreshTokenGroupBy is the group-by builder for RefreshToken entities.
 type RefreshTokenGroupBy struct {
 	config
+	selector
 	fields []string
 	fns    []AggregateFunc
 	// intermediate query (i.e. traversal path).
@@ -458,209 +462,6 @@ func (rtgb *RefreshTokenGroupBy) Scan(ctx context.Context, v interface{}) error
 	return rtgb.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (rtgb *RefreshTokenGroupBy) ScanX(ctx context.Context, v interface{}) {
-	if err := rtgb.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (rtgb *RefreshTokenGroupBy) Strings(ctx context.Context) ([]string, error) {
-	if len(rtgb.fields) > 1 {
-		return nil, errors.New("db: RefreshTokenGroupBy.Strings is not achievable when grouping more than 1 field")
-	}
-	var v []string
-	if err := rtgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (rtgb *RefreshTokenGroupBy) StringsX(ctx context.Context) []string {
-	v, err := rtgb.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (rtgb *RefreshTokenGroupBy) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = rtgb.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{refreshtoken.Label}
-	default:
-		err = fmt.Errorf("db: RefreshTokenGroupBy.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (rtgb *RefreshTokenGroupBy) StringX(ctx context.Context) string {
-	v, err := rtgb.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (rtgb *RefreshTokenGroupBy) Ints(ctx context.Context) ([]int, error) {
-	if len(rtgb.fields) > 1 {
-		return nil, errors.New("db: RefreshTokenGroupBy.Ints is not achievable when grouping more than 1 field")
-	}
-	var v []int
-	if err := rtgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (rtgb *RefreshTokenGroupBy) IntsX(ctx context.Context) []int {
-	v, err := rtgb.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (rtgb *RefreshTokenGroupBy) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = rtgb.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{refreshtoken.Label}
-	default:
-		err = fmt.Errorf("db: RefreshTokenGroupBy.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (rtgb *RefreshTokenGroupBy) IntX(ctx context.Context) int {
-	v, err := rtgb.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (rtgb *RefreshTokenGroupBy) Float64s(ctx context.Context) ([]float64, error) {
-	if len(rtgb.fields) > 1 {
-		return nil, errors.New("db: RefreshTokenGroupBy.Float64s is not achievable when grouping more than 1 field")
-	}
-	var v []float64
-	if err := rtgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (rtgb *RefreshTokenGroupBy) Float64sX(ctx context.Context) []float64 {
-	v, err := rtgb.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (rtgb *RefreshTokenGroupBy) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = rtgb.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{refreshtoken.Label}
-	default:
-		err = fmt.Errorf("db: RefreshTokenGroupBy.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (rtgb *RefreshTokenGroupBy) Float64X(ctx context.Context) float64 {
-	v, err := rtgb.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from group-by.
-// It is only allowed when executing a group-by query with one field.
-func (rtgb *RefreshTokenGroupBy) Bools(ctx context.Context) ([]bool, error) {
-	if len(rtgb.fields) > 1 {
-		return nil, errors.New("db: RefreshTokenGroupBy.Bools is not achievable when grouping more than 1 field")
-	}
-	var v []bool
-	if err := rtgb.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (rtgb *RefreshTokenGroupBy) BoolsX(ctx context.Context) []bool {
-	v, err := rtgb.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a group-by query.
-// It is only allowed when executing a group-by query with one field.
-func (rtgb *RefreshTokenGroupBy) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = rtgb.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{refreshtoken.Label}
-	default:
-		err = fmt.Errorf("db: RefreshTokenGroupBy.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (rtgb *RefreshTokenGroupBy) BoolX(ctx context.Context) bool {
-	v, err := rtgb.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (rtgb *RefreshTokenGroupBy) sqlScan(ctx context.Context, v interface{}) error {
 	for _, f := range rtgb.fields {
 		if !refreshtoken.ValidColumn(f) {
@@ -702,6 +503,7 @@ func (rtgb *RefreshTokenGroupBy) sqlQuery() *sql.Selector {
 // RefreshTokenSelect is the builder for selecting fields of RefreshToken entities.
 type RefreshTokenSelect struct {
 	*RefreshTokenQuery
+	selector
 	// intermediate query (i.e. traversal path).
 	sql *sql.Selector
 }
@@ -715,201 +517,6 @@ func (rts *RefreshTokenSelect) Scan(ctx context.Context, v interface{}) error {
 	return rts.sqlScan(ctx, v)
 }
 
-// ScanX is like Scan, but panics if an error occurs.
-func (rts *RefreshTokenSelect) ScanX(ctx context.Context, v interface{}) {
-	if err := rts.Scan(ctx, v); err != nil {
-		panic(err)
-	}
-}
-
-// Strings returns list of strings from a selector. It is only allowed when selecting one field.
-func (rts *RefreshTokenSelect) Strings(ctx context.Context) ([]string, error) {
-	if len(rts.fields) > 1 {
-		return nil, errors.New("db: RefreshTokenSelect.Strings is not achievable when selecting more than 1 field")
-	}
-	var v []string
-	if err := rts.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// StringsX is like Strings, but panics if an error occurs.
-func (rts *RefreshTokenSelect) StringsX(ctx context.Context) []string {
-	v, err := rts.Strings(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// String returns a single string from a selector. It is only allowed when selecting one field.
-func (rts *RefreshTokenSelect) String(ctx context.Context) (_ string, err error) {
-	var v []string
-	if v, err = rts.Strings(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{refreshtoken.Label}
-	default:
-		err = fmt.Errorf("db: RefreshTokenSelect.Strings returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// StringX is like String, but panics if an error occurs.
-func (rts *RefreshTokenSelect) StringX(ctx context.Context) string {
-	v, err := rts.String(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Ints returns list of ints from a selector. It is only allowed when selecting one field.
-func (rts *RefreshTokenSelect) Ints(ctx context.Context) ([]int, error) {
-	if len(rts.fields) > 1 {
-		return nil, errors.New("db: RefreshTokenSelect.Ints is not achievable when selecting more than 1 field")
-	}
-	var v []int
-	if err := rts.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// IntsX is like Ints, but panics if an error occurs.
-func (rts *RefreshTokenSelect) IntsX(ctx context.Context) []int {
-	v, err := rts.Ints(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Int returns a single int from a selector. It is only allowed when selecting one field.
-func (rts *RefreshTokenSelect) Int(ctx context.Context) (_ int, err error) {
-	var v []int
-	if v, err = rts.Ints(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{refreshtoken.Label}
-	default:
-		err = fmt.Errorf("db: RefreshTokenSelect.Ints returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// IntX is like Int, but panics if an error occurs.
-func (rts *RefreshTokenSelect) IntX(ctx context.Context) int {
-	v, err := rts.Int(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
-func (rts *RefreshTokenSelect) Float64s(ctx context.Context) ([]float64, error) {
-	if len(rts.fields) > 1 {
-		return nil, errors.New("db: RefreshTokenSelect.Float64s is not achievable when selecting more than 1 field")
-	}
-	var v []float64
-	if err := rts.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// Float64sX is like Float64s, but panics if an error occurs.
-func (rts *RefreshTokenSelect) Float64sX(ctx context.Context) []float64 {
-	v, err := rts.Float64s(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
-func (rts *RefreshTokenSelect) Float64(ctx context.Context) (_ float64, err error) {
-	var v []float64
-	if v, err = rts.Float64s(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{refreshtoken.Label}
-	default:
-		err = fmt.Errorf("db: RefreshTokenSelect.Float64s returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// Float64X is like Float64, but panics if an error occurs.
-func (rts *RefreshTokenSelect) Float64X(ctx context.Context) float64 {
-	v, err := rts.Float64(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bools returns list of bools from a selector. It is only allowed when selecting one field.
-func (rts *RefreshTokenSelect) Bools(ctx context.Context) ([]bool, error) {
-	if len(rts.fields) > 1 {
-		return nil, errors.New("db: RefreshTokenSelect.Bools is not achievable when selecting more than 1 field")
-	}
-	var v []bool
-	if err := rts.Scan(ctx, &v); err != nil {
-		return nil, err
-	}
-	return v, nil
-}
-
-// BoolsX is like Bools, but panics if an error occurs.
-func (rts *RefreshTokenSelect) BoolsX(ctx context.Context) []bool {
-	v, err := rts.Bools(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
-// Bool returns a single bool from a selector. It is only allowed when selecting one field.
-func (rts *RefreshTokenSelect) Bool(ctx context.Context) (_ bool, err error) {
-	var v []bool
-	if v, err = rts.Bools(ctx); err != nil {
-		return
-	}
-	switch len(v) {
-	case 1:
-		return v[0], nil
-	case 0:
-		err = &NotFoundError{refreshtoken.Label}
-	default:
-		err = fmt.Errorf("db: RefreshTokenSelect.Bools returned %d results when one was expected", len(v))
-	}
-	return
-}
-
-// BoolX is like Bool, but panics if an error occurs.
-func (rts *RefreshTokenSelect) BoolX(ctx context.Context) bool {
-	v, err := rts.Bool(ctx)
-	if err != nil {
-		panic(err)
-	}
-	return v
-}
-
 func (rts *RefreshTokenSelect) sqlScan(ctx context.Context, v interface{}) error {
 	rows := &sql.Rows{}
 	query, args := rts.sql.Query()
diff --git a/storage/ent/db/refreshtoken_update.go b/storage/ent/db/refreshtoken_update.go
index f6e6e61b..6c11c7f7 100644
--- a/storage/ent/db/refreshtoken_update.go
+++ b/storage/ent/db/refreshtoken_update.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -421,7 +421,7 @@ func (rtu *RefreshTokenUpdate) sqlSave(ctx context.Context) (n int, err error) {
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{refreshtoken.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return 0, err
 	}
@@ -627,9 +627,15 @@ func (rtuo *RefreshTokenUpdateOne) Save(ctx context.Context) (*RefreshToken, err
 			}
 			mut = rtuo.hooks[i](mut)
 		}
-		if _, err := mut.Mutate(ctx, rtuo.mutation); err != nil {
+		v, err := mut.Mutate(ctx, rtuo.mutation)
+		if err != nil {
 			return nil, err
 		}
+		nv, ok := v.(*RefreshToken)
+		if !ok {
+			return nil, fmt.Errorf("unexpected node type %T returned from RefreshTokenMutation", v)
+		}
+		node = nv
 	}
 	return node, err
 }
@@ -856,7 +862,7 @@ func (rtuo *RefreshTokenUpdateOne) sqlSave(ctx context.Context) (_node *RefreshT
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{refreshtoken.Label}
 		} else if sqlgraph.IsConstraintError(err) {
-			err = &ConstraintError{err.Error(), err}
+			err = &ConstraintError{msg: err.Error(), wrap: err}
 		}
 		return nil, err
 	}
diff --git a/storage/ent/db/runtime.go b/storage/ent/db/runtime.go
index d3123b3f..797c9761 100644
--- a/storage/ent/db/runtime.go
+++ b/storage/ent/db/runtime.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
@@ -142,6 +142,14 @@ func init() {
 	devicetokenDescStatus := devicetokenFields[1].Descriptor()
 	// devicetoken.StatusValidator is a validator for the "status" field. It is called by the builders before save.
 	devicetoken.StatusValidator = devicetokenDescStatus.Validators[0].(func(string) error)
+	// devicetokenDescCodeChallenge is the schema descriptor for code_challenge field.
+	devicetokenDescCodeChallenge := devicetokenFields[6].Descriptor()
+	// devicetoken.DefaultCodeChallenge holds the default value on creation for the code_challenge field.
+	devicetoken.DefaultCodeChallenge = devicetokenDescCodeChallenge.Default.(string)
+	// devicetokenDescCodeChallengeMethod is the schema descriptor for code_challenge_method field.
+	devicetokenDescCodeChallengeMethod := devicetokenFields[7].Descriptor()
+	// devicetoken.DefaultCodeChallengeMethod holds the default value on creation for the code_challenge_method field.
+	devicetoken.DefaultCodeChallengeMethod = devicetokenDescCodeChallengeMethod.Default.(string)
 	keysFields := schema.Keys{}.Fields()
 	_ = keysFields
 	// keysDescID is the schema descriptor for id field.
diff --git a/storage/ent/db/runtime/runtime.go b/storage/ent/db/runtime/runtime.go
index 8c201fe1..9000ac47 100644
--- a/storage/ent/db/runtime/runtime.go
+++ b/storage/ent/db/runtime/runtime.go
@@ -1,10 +1,10 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package runtime
 
 // The schema-stitching logic is generated in github.com/dexidp/dex/storage/ent/db/runtime.go
 
 const (
-	Version = "v0.10.1"                                         // Version of ent codegen.
-	Sum     = "h1:dM5h4Zk6yHGIgw4dCqVzGw3nWgpGYJiV4/kyHEF6PFo=" // Sum of ent codegen.
+	Version = "v0.11.2"                                         // Version of ent codegen.
+	Sum     = "h1:UM2/BUhF2FfsxPHRxLjQbhqJNaDdVlOwNIAMLs2jyto=" // Sum of ent codegen.
 )
diff --git a/storage/ent/db/tx.go b/storage/ent/db/tx.go
index 0107193b..73d19447 100644
--- a/storage/ent/db/tx.go
+++ b/storage/ent/db/tx.go
@@ -1,4 +1,4 @@
-// Code generated by entc, DO NOT EDIT.
+// Code generated by ent, DO NOT EDIT.
 
 package db
 
diff --git a/storage/ent/mysql.go b/storage/ent/mysql.go
index 2d3c833b..4a9407f9 100644
--- a/storage/ent/mysql.go
+++ b/storage/ent/mysql.go
@@ -13,7 +13,6 @@ import (
 	"time"
 
 	entSQL "entgo.io/ent/dialect/sql"
-	"entgo.io/ent/dialect/sql/schema"
 	"github.com/go-sql-driver/mysql" // Register mysql driver.
 
 	"github.com/dexidp/dex/pkg/log"
@@ -54,7 +53,7 @@ func (m *MySQL) Open(logger log.Logger) (storage.Storage, error) {
 		client.WithTxIsolationLevel(sql.LevelSerializable),
 	)
 
-	if err := databaseClient.Schema().Create(context.TODO(), schema.WithAtlas(false)); err != nil {
+	if err := databaseClient.Schema().Create(context.TODO()); err != nil {
 		return nil, err
 	}
 
diff --git a/storage/ent/postgres.go b/storage/ent/postgres.go
index c52c2902..1953f599 100644
--- a/storage/ent/postgres.go
+++ b/storage/ent/postgres.go
@@ -12,7 +12,6 @@ import (
 	"time"
 
 	entSQL "entgo.io/ent/dialect/sql"
-	"entgo.io/ent/dialect/sql/schema"
 	_ "github.com/lib/pq" // Register postgres driver.
 
 	"github.com/dexidp/dex/pkg/log"
@@ -55,7 +54,7 @@ func (p *Postgres) Open(logger log.Logger) (storage.Storage, error) {
 		client.WithTxIsolationLevel(sql.LevelSerializable),
 	)
 
-	if err := databaseClient.Schema().Create(context.TODO(), schema.WithAtlas(false)); err != nil {
+	if err := databaseClient.Schema().Create(context.TODO()); err != nil {
 		return nil, err
 	}
 
diff --git a/storage/ent/schema/devicetoken.go b/storage/ent/schema/devicetoken.go
index 29927e2b..dc0e7b8e 100644
--- a/storage/ent/schema/devicetoken.go
+++ b/storage/ent/schema/devicetoken.go
@@ -8,12 +8,14 @@ import (
 /* Original SQL table:
 create table device_token
 (
-    device_code   text      not null primary key,
-    status        text      not null,
-    token         blob,
-    expiry        timestamp not null,
-    last_request  timestamp not null,
-    poll_interval integer   not null
+    device_code           text            not null primary key,
+    status                text            not null,
+    token                 blob,
+    expiry                timestamp       not null,
+    last_request          timestamp       not null,
+    poll_interval         integer         not null,
+    code_challenge        text default '' not null,
+    code_challenge_method text default '' not null
 );
 */
 
@@ -38,6 +40,12 @@ func (DeviceToken) Fields() []ent.Field {
 		field.Time("last_request").
 			SchemaType(timeSchema),
 		field.Int("poll_interval"),
+		field.Text("code_challenge").
+			SchemaType(textSchema).
+			Default(""),
+		field.Text("code_challenge_method").
+			SchemaType(textSchema).
+			Default(""),
 	}
 }
 
diff --git a/storage/ent/sqlite.go b/storage/ent/sqlite.go
index bb98ac06..c0b442f4 100644
--- a/storage/ent/sqlite.go
+++ b/storage/ent/sqlite.go
@@ -6,7 +6,6 @@ import (
 	"strings"
 
 	"entgo.io/ent/dialect/sql"
-	"entgo.io/ent/dialect/sql/schema"
 	_ "github.com/mattn/go-sqlite3" // Register sqlite driver.
 
 	"github.com/dexidp/dex/pkg/log"
@@ -42,7 +41,7 @@ func (s *SQLite3) Open(logger log.Logger) (storage.Storage, error) {
 		client.WithHasher(sha256.New),
 	)
 
-	if err := databaseClient.Schema().Create(context.TODO(), schema.WithAtlas(false)); err != nil {
+	if err := databaseClient.Schema().Create(context.TODO()); err != nil {
 		return nil, err
 	}
 
diff --git a/storage/etcd/etcd.go b/storage/etcd/etcd.go
index 63fa7bc2..13e815ec 100644
--- a/storage/etcd/etcd.go
+++ b/storage/etcd/etcd.go
@@ -605,8 +605,11 @@ func (c *conn) CreateDeviceToken(t storage.DeviceToken) error {
 func (c *conn) GetDeviceToken(deviceCode string) (t storage.DeviceToken, err error) {
 	ctx, cancel := context.WithTimeout(context.Background(), defaultStorageTimeout)
 	defer cancel()
-	err = c.getKey(ctx, keyID(deviceTokenPrefix, deviceCode), &t)
-	return t, err
+	var dt DeviceToken
+	if err = c.getKey(ctx, keyID(deviceTokenPrefix, deviceCode), &dt); err == nil {
+		t = toStorageDeviceToken(dt)
+	}
+	return
 }
 
 func (c *conn) listDeviceTokens(ctx context.Context) (deviceTokens []DeviceToken, err error) {
diff --git a/storage/etcd/types.go b/storage/etcd/types.go
index 0d64ff74..91199ab6 100644
--- a/storage/etcd/types.go
+++ b/storage/etcd/types.go
@@ -285,6 +285,8 @@ type DeviceToken struct {
 	Expiry              time.Time `json:"expiry"`
 	LastRequestTime     time.Time `json:"last_request"`
 	PollIntervalSeconds int       `json:"poll_interval"`
+	CodeChallenge       string    `json:"code_challenge,omitempty"`
+	CodeChallengeMethod string    `json:"code_challenge_method,omitempty"`
 }
 
 func fromStorageDeviceToken(t storage.DeviceToken) DeviceToken {
@@ -295,6 +297,8 @@ func fromStorageDeviceToken(t storage.DeviceToken) DeviceToken {
 		Expiry:              t.Expiry,
 		LastRequestTime:     t.LastRequestTime,
 		PollIntervalSeconds: t.PollIntervalSeconds,
+		CodeChallenge:       t.PKCE.CodeChallenge,
+		CodeChallengeMethod: t.PKCE.CodeChallengeMethod,
 	}
 }
 
@@ -306,5 +310,9 @@ func toStorageDeviceToken(t DeviceToken) storage.DeviceToken {
 		Expiry:              t.Expiry,
 		LastRequestTime:     t.LastRequestTime,
 		PollIntervalSeconds: t.PollIntervalSeconds,
+		PKCE: storage.PKCE{
+			CodeChallenge:       t.CodeChallenge,
+			CodeChallengeMethod: t.CodeChallengeMethod,
+		},
 	}
 }
diff --git a/storage/kubernetes/types.go b/storage/kubernetes/types.go
index cdcdc321..a5ec29af 100644
--- a/storage/kubernetes/types.go
+++ b/storage/kubernetes/types.go
@@ -806,6 +806,8 @@ type DeviceToken struct {
 	Expiry              time.Time `json:"expiry"`
 	LastRequestTime     time.Time `json:"last_request"`
 	PollIntervalSeconds int       `json:"poll_interval"`
+	CodeChallenge       string    `json:"code_challenge,omitempty"`
+	CodeChallengeMethod string    `json:"code_challenge_method,omitempty"`
 }
 
 // DeviceTokenList is a list of DeviceTokens.
@@ -830,6 +832,8 @@ func (cli *client) fromStorageDeviceToken(t storage.DeviceToken) DeviceToken {
 		Expiry:              t.Expiry,
 		LastRequestTime:     t.LastRequestTime,
 		PollIntervalSeconds: t.PollIntervalSeconds,
+		CodeChallenge:       t.PKCE.CodeChallenge,
+		CodeChallengeMethod: t.PKCE.CodeChallengeMethod,
 	}
 	return req
 }
@@ -842,5 +846,9 @@ func toStorageDeviceToken(t DeviceToken) storage.DeviceToken {
 		Expiry:              t.Expiry,
 		LastRequestTime:     t.LastRequestTime,
 		PollIntervalSeconds: t.PollIntervalSeconds,
+		PKCE: storage.PKCE{
+			CodeChallenge:       t.CodeChallenge,
+			CodeChallengeMethod: t.CodeChallengeMethod,
+		},
 	}
 }
diff --git a/storage/sql/crud.go b/storage/sql/crud.go
index 0df995c9..8ac4204f 100644
--- a/storage/sql/crud.go
+++ b/storage/sql/crud.go
@@ -929,12 +929,12 @@ func (c *conn) CreateDeviceRequest(d storage.DeviceRequest) error {
 func (c *conn) CreateDeviceToken(t storage.DeviceToken) error {
 	_, err := c.Exec(`
 		insert into device_token (
-			device_code, status, token, expiry, last_request, poll_interval
+			device_code, status, token, expiry, last_request, poll_interval, code_challenge, code_challenge_method
 		)
 		values (
-			$1, $2, $3, $4, $5, $6
+			$1, $2, $3, $4, $5, $6, $7, $8
 		);`,
-		t.DeviceCode, t.Status, t.Token, t.Expiry, t.LastRequestTime, t.PollIntervalSeconds,
+		t.DeviceCode, t.Status, t.Token, t.Expiry, t.LastRequestTime, t.PollIntervalSeconds, t.PKCE.CodeChallenge, t.PKCE.CodeChallengeMethod,
 	)
 	if err != nil {
 		if c.alreadyExistsCheck(err) {
@@ -974,10 +974,10 @@ func (c *conn) GetDeviceToken(deviceCode string) (storage.DeviceToken, error) {
 func getDeviceToken(q querier, deviceCode string) (a storage.DeviceToken, err error) {
 	err = q.QueryRow(`
 		select
-            status, token, expiry, last_request, poll_interval
+            status, token, expiry, last_request, poll_interval, code_challenge, code_challenge_method
 		from device_token where device_code = $1;
 	`, deviceCode).Scan(
-		&a.Status, &a.Token, &a.Expiry, &a.LastRequestTime, &a.PollIntervalSeconds,
+		&a.Status, &a.Token, &a.Expiry, &a.LastRequestTime, &a.PollIntervalSeconds, &a.PKCE.CodeChallenge, &a.PKCE.CodeChallengeMethod,
 	)
 	if err != nil {
 		if err == sql.ErrNoRows {
@@ -1004,11 +1004,13 @@ func (c *conn) UpdateDeviceToken(deviceCode string, updater func(old storage.Dev
 				status = $1, 
 				token = $2,
 				last_request = $3,
-				poll_interval = $4
+				poll_interval = $4,
+				code_challenge = $5,
+				code_challenge_method = $6
 			where
-				device_code = $5
+				device_code = $7
 		`,
-			r.Status, r.Token, r.LastRequestTime, r.PollIntervalSeconds, r.DeviceCode,
+			r.Status, r.Token, r.LastRequestTime, r.PollIntervalSeconds, r.PKCE.CodeChallenge, r.PKCE.CodeChallengeMethod, r.DeviceCode,
 		)
 		if err != nil {
 			return fmt.Errorf("update device token: %v", err)
diff --git a/storage/sql/migrate.go b/storage/sql/migrate.go
index 063e1789..83e9c20d 100644
--- a/storage/sql/migrate.go
+++ b/storage/sql/migrate.go
@@ -281,6 +281,16 @@ var migrations = []migration{
 				add column obsolete_token text default '';`,
 		},
 	},
+	{
+		stmts: []string{
+			`
+			alter table device_token
+				add column code_challenge text not null default '';`,
+			`
+			alter table device_token
+				add column code_challenge_method text not null default '';`,
+		},
+	},
 	{
 		stmts: []string{
 			`
diff --git a/storage/storage.go b/storage/storage.go
index 060e792c..198a70c8 100644
--- a/storage/storage.go
+++ b/storage/storage.go
@@ -436,4 +436,5 @@ type DeviceToken struct {
 	Expiry              time.Time
 	LastRequestTime     time.Time
 	PollIntervalSeconds int
+	PKCE                PKCE
 }