diff --git a/deploy/crds/keycloak.org_keycloaks_crd.yaml b/deploy/crds/keycloak.org_keycloaks_crd.yaml
index 49ce85cb94e748e0806ff9fa7ed215236991c31a..0f0cfd19c1dff5088e49aad1d7c114a706b352e4 100644
--- a/deploy/crds/keycloak.org_keycloaks_crd.yaml
+++ b/deploy/crds/keycloak.org_keycloaks_crd.yaml
@@ -54,6 +54,10 @@ spec:
                 description: Contains configuration for external Keycloak instances.
                   Unmanaged needs to be set to true to use this.
                 properties:
+                  contextRoot:
+                    description: Context root for Keycloak. If not set, the default
+                      "/auth/" is used. Must end with "/".
+                    type: string
                   enabled:
                     description: If set to true, this Keycloak will be treated as
                       an external instance. The unmanaged field also needs to be set
diff --git a/pkg/apis/keycloak/v1alpha1/keycloak_types.go b/pkg/apis/keycloak/v1alpha1/keycloak_types.go
index 4c1f302c4b58bde9fd7609aba5876e5bbd548c92..91e412ff3828155d56ff900579e8318b3b4fb893 100644
--- a/pkg/apis/keycloak/v1alpha1/keycloak_types.go
+++ b/pkg/apis/keycloak/v1alpha1/keycloak_types.go
@@ -178,6 +178,9 @@ type KeycloakExternal struct {
 	// The URL to use for the keycloak admin API. Needs to be set if external is true.
 	// +optional
 	URL string `json:"url,omitempty"`
+	// Context root for Keycloak. If not set, the default "/auth/" is used.
+	// Must end with "/".
+	ContextRoot string `json:"contextRoot,omitempty"`
 }
 
 type KeycloakExternalAccess struct {
diff --git a/pkg/common/client.go b/pkg/common/client.go
index d83442aa5baf4d5c1f9ceb5f6a7a95d6ad4bce27..07eefa3eb2484a442c2a47fa0f19bf48991bc482 100644
--- a/pkg/common/client.go
+++ b/pkg/common/client.go
@@ -24,7 +24,7 @@ import (
 )
 
 const (
-	authURL = "auth/realms/master/protocol/openid-connect/token"
+	authURL = "realms/master/protocol/openid-connect/token"
 )
 
 type Requester interface {
@@ -32,9 +32,10 @@ type Requester interface {
 }
 
 type Client struct {
-	requester Requester
-	URL       string
-	token     string
+	requester   Requester
+	URL         string
+	contextRoot string
+	token       string
 }
 
 // T is a generic type for keycloak spec resources
@@ -50,7 +51,7 @@ func (c *Client) create(obj T, resourcePath, resourceName string) (string, error
 
 	req, err := http.NewRequest(
 		"POST",
-		fmt.Sprintf("%s/auth/admin/%s", c.URL, resourcePath),
+		fmt.Sprintf("%sadmin/%s", c.GetFullKeycloakPath(), resourcePath),
 		bytes.NewBuffer(jsonValue),
 	)
 	if err != nil {
@@ -235,7 +236,7 @@ func (c *Client) CreateIdentityProvider(identityProvider *v1alpha1.KeycloakIdent
 
 // Generic get function for returning a Keycloak resource
 func (c *Client) get(resourcePath, resourceName string, unMarshalFunc func(body []byte) (T, error)) (T, error) {
-	u := fmt.Sprintf("%s/auth/admin/%s", c.URL, resourcePath)
+	u := fmt.Sprintf("%sadmin/%s", c.GetFullKeycloakPath(), resourcePath)
 	req, err := http.NewRequest(
 		"GET",
 		u,
@@ -394,7 +395,7 @@ func (c *Client) update(obj T, resourcePath, resourceName string) error {
 
 	req, err := http.NewRequest(
 		"PUT",
-		fmt.Sprintf("%s/auth/admin/%s", c.URL, resourcePath),
+		fmt.Sprintf("%sadmin/%s", c.GetFullKeycloakPath(), resourcePath),
 		bytes.NewBuffer(jsonValue),
 	)
 	if err != nil {
@@ -454,7 +455,7 @@ func (c *Client) UpdateClientOptionalClientScope(specClient *v1alpha1.KeycloakAP
 func (c *Client) delete(resourcePath, resourceName string, obj T) error {
 	req, err := http.NewRequest(
 		"DELETE",
-		fmt.Sprintf("%s/auth/admin/%s", c.URL, resourcePath),
+		fmt.Sprintf("%sadmin/%s", c.GetFullKeycloakPath(), resourcePath),
 		nil,
 	)
 
@@ -465,7 +466,7 @@ func (c *Client) delete(resourcePath, resourceName string, obj T) error {
 		}
 		req, err = http.NewRequest(
 			"DELETE",
-			fmt.Sprintf("%s/auth/admin/%s", c.URL, resourcePath),
+			fmt.Sprintf("%sadmin/%s", c.GetFullKeycloakPath(), resourcePath),
 			bytes.NewBuffer(jsonValue),
 		)
 		if err != nil {
@@ -550,7 +551,7 @@ func (c *Client) DeleteAuthenticatorConfig(configID, realmName string) error {
 func (c *Client) list(resourcePath, resourceName string, unMarshalListFunc func(body []byte) (T, error)) (T, error) {
 	req, err := http.NewRequest(
 		"GET",
-		fmt.Sprintf("%s/auth/admin/%s", c.URL, resourcePath),
+		fmt.Sprintf("%sadmin/%s", c.GetFullKeycloakPath(), resourcePath),
 		nil,
 	)
 	if err != nil {
@@ -806,7 +807,7 @@ func (c *Client) ListAuthenticationExecutionsForFlow(flowAlias, realmName string
 }
 
 func (c *Client) Ping() error {
-	u := c.URL + "/auth/"
+	u := c.GetFullKeycloakPath()
 	req, err := http.NewRequest("GET", u, nil)
 	if err != nil {
 		logrus.Errorf("error creating ping request %+v", err)
@@ -854,7 +855,7 @@ func (c *Client) login(user, pass string) error {
 
 	req, err := http.NewRequest(
 		"POST",
-		fmt.Sprintf("%s/%s", c.URL, authURL),
+		c.GetFullKeycloakPath()+authURL,
 		strings.NewReader(form.Encode()),
 	)
 	if err != nil {
@@ -881,8 +882,8 @@ func (c *Client) login(user, pass string) error {
 	}
 
 	if tokenRes.Error != "" {
-		logrus.Errorf("error with request: " + tokenRes.ErrorDescription)
-		return errors.Errorf(tokenRes.ErrorDescription)
+		logrus.Errorf("error with request: " + tokenRes.Error)
+		return errors.Errorf(tokenRes.Error)
 	}
 
 	c.token = tokenRes.AccessToken
@@ -899,6 +900,9 @@ func defaultRequester(serverCert []byte) (Requester, error) {
 	transport := http.DefaultTransport.(*http.Transport).Clone()
 	transport.TLSClientConfig = tlsConfig
 
+	// https://github.com/keycloak/keycloak/issues/13315
+	transport.ForceAttemptHTTP2 = false
+
 	c := &http.Client{Transport: transport, Timeout: time.Second * 10}
 	return c, nil
 }
@@ -1054,9 +1058,15 @@ func (i *LocalConfigKeycloakFactory) AuthenticatedClient(kc v1alpha1.Keycloak, i
 		return nil, err
 	}
 
+	var contextRoot string
+	if kc.Spec.External.Enabled && kc.Spec.Unmanaged {
+		contextRoot += kc.Spec.External.ContextRoot
+	}
+
 	client := &Client{
-		URL:       kcURL,
-		requester: requester,
+		URL:         kcURL,
+		requester:   requester,
+		contextRoot: contextRoot,
 	}
 	if err := client.login(user, pass); err != nil {
 		return nil, err
@@ -1124,3 +1134,13 @@ func validateKeycloakURL(url string, requester Requester) (string, error) {
 	_ = res.Body.Close()
 	return url, nil
 }
+
+func (c *Client) GetFullKeycloakPath() string {
+	URL := c.URL
+	if c.contextRoot != "" {
+		URL += c.contextRoot
+	} else {
+		URL += "/auth/"
+	}
+	return URL
+}
diff --git a/pkg/common/client_test.go b/pkg/common/client_test.go
index 5f0266c66a6ac914de755147f8158b1fa23ea112..c33b7946ac36faa02ae7fb30f0894e7ef35783c7 100644
--- a/pkg/common/client_test.go
+++ b/pkg/common/client_test.go
@@ -349,3 +349,18 @@ func TestClient_useKeycloakServerCertificate(t *testing.T) {
 	defer resp.Body.Close()
 	assert.Equal(t, resp.StatusCode, 200)
 }
+
+func TestClient_GetFullKeycloakPath(t *testing.T) {
+	serverURL := "https://foo.bar:8080"
+	customContext := "/"
+
+	client := Client{
+		URL:         serverURL,
+		contextRoot: customContext,
+	}
+	assert.Equal(t, serverURL+customContext, client.GetFullKeycloakPath())
+
+	client.contextRoot = ""
+
+	assert.Equal(t, serverURL+"/auth/", client.GetFullKeycloakPath())
+}