diff --git a/storage/kubernetes/client.go b/storage/kubernetes/client.go
index bfdc915113c9315d248d34dc66de961e8221a807..2d7420083f13999ff8165130776ebc75e44a4f8a 100644
--- a/storage/kubernetes/client.go
+++ b/storage/kubernetes/client.go
@@ -322,6 +322,32 @@ func loadKubeConfig(kubeConfigPath string) (cluster k8sapi.Cluster, user k8sapi.
 	return
 }
 
+func namespaceFromServiceAccountJWT(s string) (string, error) {
+	// The service account token is just a JWT. Parse it as such.
+	parts := strings.Split(s, ".")
+	if len(parts) < 2 {
+		// It's extremely important we don't log the actual service account token.
+		return "", fmt.Errorf("malformed service account token: expected 3 parts got %d", len(parts))
+	}
+	payload, err := base64.RawURLEncoding.DecodeString(parts[1])
+	if err != nil {
+		return "", fmt.Errorf("malformed service account token: %v", err)
+	}
+	var data struct {
+		// The claim Kubernetes uses to identify which namespace a service account belongs to.
+		//
+		// See: https://github.com/kubernetes/kubernetes/blob/v1.4.3/pkg/serviceaccount/jwt.go#L42
+		Namespace string `json:"kubernetes.io/serviceaccount/namespace"`
+	}
+	if err := json.Unmarshal(payload, &data); err != nil {
+		return "", fmt.Errorf("malformed service account token: %v", err)
+	}
+	if data.Namespace == "" {
+		return "", errors.New(`jwt claim "kubernetes.io/serviceaccount/namespace" not found`)
+	}
+	return data.Namespace, nil
+}
+
 func inClusterConfig() (cluster k8sapi.Cluster, user k8sapi.AuthInfo, namespace string, err error) {
 	host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
 	if len(host) == 0 || len(port) == 0 {
@@ -332,17 +358,20 @@ func inClusterConfig() (cluster k8sapi.Cluster, user k8sapi.AuthInfo, namespace
 		Server:               "https://" + host + ":" + port,
 		CertificateAuthority: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt",
 	}
-
-	if namespace = os.Getenv("KUBERNETES_POD_NAMESPACE"); namespace == "" {
-		err = fmt.Errorf("unable to load in-cluster configuration, KUBERNETES_POD_NAMESPACE must be defined")
-		return
-	}
-
 	token, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
 	if err != nil {
 		return
 	}
 	user = k8sapi.AuthInfo{Token: string(token)}
+
+	if namespace = os.Getenv("KUBERNETES_POD_NAMESPACE"); namespace == "" {
+		namespace, err = namespaceFromServiceAccountJWT(user.Token)
+		if err != nil {
+			err = fmt.Errorf("failed to inspect service account token: %v", err)
+			return
+		}
+	}
+
 	return
 }
 
diff --git a/storage/kubernetes/client_test.go b/storage/kubernetes/client_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..92ae204a5b7c2356f97c7ce73fea6e7fda9048cf
--- /dev/null
+++ b/storage/kubernetes/client_test.go
@@ -0,0 +1,60 @@
+package kubernetes
+
+import "testing"
+
+func TestNamespaceFromServiceAccountJWT(t *testing.T) {
+	namespace, err := namespaceFromServiceAccountJWT(serviceAccountToken)
+	if err != nil {
+		t.Fatal(err)
+	}
+	wantNamespace := "dex-test-namespace"
+	if namespace != wantNamespace {
+		t.Errorf("expected namespace %q got %q", wantNamespace, namespace)
+	}
+}
+
+var serviceAccountToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZXgtdGVzdC1uYW1lc3BhY2UiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlY3JldC5uYW1lIjoiZG90aGVyb2JvdC1zZWNyZXQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZG90aGVyb2JvdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjQyYjJhOTRmLTk4MjAtMTFlNi1iZDc0LTJlZmQzOGYxMjYxYyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZXgtdGVzdC1uYW1lc3BhY2U6ZG90aGVyb2JvdCJ9.KViBpPwCiBwxDvAjYUUXoVvLVwqV011aLlYQpNtX12Bh8M-QAFch-3RWlo_SR00bcdFg_nZo9JKACYlF_jHMEsf__PaYms9r7vEaSg0jPfkqnL2WXZktzQRyLBr0n-bxeUrbwIWsKOAC0DfFB5nM8XoXljRmq8yAx8BAdmQp7MIFb4EOV9nYthhua6pjzYyaFSiDiYTjw7HtXOvoL8oepodJ3-37pUKS8vdBvnvUoqC4M1YAhkO5L36JF6KV_RfmG8GPEdNQfXotHcsR-3jKi1n8S5l7Xd-rhrGOhSGQizH3dORzo9GvBAhYeqbq1O-NLzm2EQUiMQayIUx7o4g3Kw"
+
+// The following program was used to generate the example token. Since we don't want to
+// import Kubernetes, just leave it as a comment.
+
+/*
+package main
+
+import (
+	"crypto/rand"
+	"crypto/rsa"
+	"fmt"
+	"log"
+
+	"k8s.io/kubernetes/pkg/api"
+	"k8s.io/kubernetes/pkg/serviceaccount"
+	"k8s.io/kubernetes/pkg/util/uuid"
+)
+
+func main() {
+	key, err := rsa.GenerateKey(rand.Reader, 2048)
+	if err != nil {
+		log.Fatal(err)
+	}
+	sa := api.ServiceAccount{
+		ObjectMeta: api.ObjectMeta{
+			Namespace: "dex-test-namespace",
+			Name:      "dotherobot",
+			UID:       uuid.NewUUID(),
+		},
+	}
+	secret := api.Secret{
+		ObjectMeta: api.ObjectMeta{
+			Namespace: "dex-test-namespace",
+			Name:      "dotherobot-secret",
+			UID:       uuid.NewUUID(),
+		},
+	}
+	token, err := serviceaccount.JWTTokenGenerator(key).GenerateToken(sa, secret)
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println(token)
+}
+*/