diff --git a/chart/drupalsite-operator/templates/manager-deploy.yaml b/chart/drupalsite-operator/templates/manager-deploy.yaml
index b953eed59005b6415fae4ac80b799c6de58249d2..887b93968ef43a8ae52bcb9efe72e3f3bc60aff1 100644
--- a/chart/drupalsite-operator/templates/manager-deploy.yaml
+++ b/chart/drupalsite-operator/templates/manager-deploy.yaml
@@ -26,6 +26,7 @@ spec:
         - --sitebuilder-image={{.Values.drupalsiteOperator.sitebuilderImage}}
         - --php-fpm-exporter-image={{.Values.drupalsiteOperator.phpFpmExporterImage}}
         - --webdav-image={{.Values.drupalsiteOperator.webdavImage}}
+        - --ssoproxy-image={{.Values.drupalsiteOperator.ssoProxyImage}}
         - --zap-stacktrace-level={{.Values.drupalsiteOperator.logStacktraceLevel}}
         - --zap-log-level={{.Values.drupalsiteOperator.logLevel}}
         - --parallel-thread-count={{.Values.drupalsiteOperator.parallelThreadCount}}
diff --git a/chart/drupalsite-operator/values.yaml b/chart/drupalsite-operator/values.yaml
index d08e4c7441065bd45d3bc6f54af76a6c2547df6e..1ca025a98567d9bafcf200fe15d635c299ae38b8 100644
--- a/chart/drupalsite-operator/values.yaml
+++ b/chart/drupalsite-operator/values.yaml
@@ -19,6 +19,7 @@ drupalsiteOperator:
   sitebuilderImage: "gitlab-registry.cern.ch/drupal/paas/cern-drupal-distribution/site-builder"
   phpFpmExporterImage: "gitlab-registry.cern.ch/drupal/paas/php-fpm-prometheus-exporter:RELEASE.2021.06.02T09-41-38Z"
   webdavImage: "gitlab-registry.cern.ch/drupal/paas/sabredav/webdav:RELEASE-2021.10.12T17-55-06Z"
+  ssoProxyImage: "quay.io/oauth2-proxy/oauth2-proxy:latest"
   # Zap Level to configure the verbosity of logging. Can be one of 'debug', 'info', 'error', or any integer value > 0 which corresponds to custom debug levels of increasing verbosity
   logLevel: "3"
   # Zap Level at and above which stacktraces are captured (one of 'info', 'error')
diff --git a/controllers/drupalsite_controller.go b/controllers/drupalsite_controller.go
index fa0ac7ca6e6372d4a422b530879b67a59f95592f..715687b9468c9495f8c6d8efd78a667207bb46a0 100644
--- a/controllers/drupalsite_controller.go
+++ b/controllers/drupalsite_controller.go
@@ -49,6 +49,8 @@ const (
 	debugAnnotation      = "debug"
 	adminPauseAnnotation = "admin-pause-reconcile"
 	oidcSecretName       = "oidc-client-secret"
+
+	ssoProxyLabel = "drupal.okd.cern.ch/full-sso"
 )
 
 var (
@@ -58,6 +60,8 @@ var (
 	PhpFpmExporterImage string
 	// WebDAVImage refers to the webdav image name
 	WebDAVImage string
+	// SSOProxyImage refers to the sso proxy image link
+	SSOProxyImage string
 	// SMTPHost used by Drupal server pods to send emails
 	SMTPHost string
 	// VeleroNamespace refers to the namespace of the velero server to create backups
@@ -224,6 +228,28 @@ func (r *DrupalSiteReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 		return r.updateCRStatusOrFailReconcile(ctx, log, drupalSite)
 	}
 
+	// Mirror SSO Proxy label from namespace, if it exists
+	namespace := &corev1.Namespace{}
+	err = r.Get(ctx, types.NamespacedName{Name: drupalSite.Namespace}, namespace)
+	if err != nil {
+		if k8sapierrors.IsNotFound(err) {
+			// Request object not found, could have been deleted after reconcile request.
+			// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
+			// Return and don't requeue
+			log.V(3).Info("Namespace resource not found. Ignoring since object must be deleted")
+			return ctrl.Result{}, nil
+		}
+		// Error reading the object - requeue the request.
+		log.Error(err, "Failed to get Namespace")
+	}
+	if drupalSite.Labels == nil {
+		drupalSite.Labels = map[string]string{}
+	}
+	if namespace.Labels[ssoProxyLabel] == "true" && drupalSite.Labels[ssoProxyLabel] != "true" {
+		drupalSite.Labels[ssoProxyLabel] = "true"
+		return r.updateCRorFailReconcile(ctx, log, drupalSite)
+	}
+
 	// 2. Check all conditions and update them if needed
 	update := false
 
diff --git a/controllers/drupalsite_resources.go b/controllers/drupalsite_resources.go
index d8961b75fb51b47766de350b96668b1f2b10fc07..b4f25a240c59f9cda61cd184c710944019446b5e 100644
--- a/controllers/drupalsite_resources.go
+++ b/controllers/drupalsite_resources.go
@@ -24,7 +24,6 @@ import (
 	"io/ioutil"
 	"math/rand"
 	"net/url"
-	"path"
 	"strconv"
 	"time"
 
@@ -61,6 +60,8 @@ const (
 	// Variable to set the used Memory for all Jobs generated by the Operator
 	jobMemoryRequest string = "512Mi"
 	jobMemoryLimit   string = "4Gi"
+	// ProxyPort servin port
+	ssoProxyPort = 8989
 )
 
 var (
@@ -743,8 +744,16 @@ func deploymentForDrupalSite(currentobject *appsv1.Deployment, databaseSecret st
 	}
 	currentobject.Annotations["alpha.image.policy.openshift.io/resolve-names"] = "*"
 
+	ssoProxyEnabled := false
+	if d.Labels[ssoProxyLabel] == "true" {
+		ssoProxyEnabled = true
+	}
+
 	if currentobject.CreationTimestamp.IsZero() {
 		currentobject.Spec.Template.Spec.Containers = []corev1.Container{{Name: "nginx"}, {Name: "php-fpm"}, {Name: "php-fpm-exporter"}, {Name: "webdav"}, {Name: "cron"}, {Name: "drupal-logs"}}
+		if ssoProxyEnabled {
+			currentobject.Spec.Template.Spec.Containers = []corev1.Container{{Name: "nginx"}, {Name: "php-fpm"}, {Name: "php-fpm-exporter"}, {Name: "webdav"}, {Name: "cron"}, {Name: "drupal-logs"}, {Name: "sso-proxy"}}
+		}
 	} else {
 		containerExists("nginx", currentobject)
 		containerExists("php-fpm", currentobject)
@@ -752,6 +761,11 @@ func deploymentForDrupalSite(currentobject *appsv1.Deployment, databaseSecret st
 		containerExists("webdav", currentobject)
 		containerExists("cron", currentobject)
 		containerExists("drupal-logs", currentobject)
+		if ssoProxyEnabled {
+			containerExists("sso-proxy", currentobject)
+		} else {
+			containerRemove("sso-proxy", currentobject)
+		}
 	}
 
 	// Settings only on creation (not enforced)
@@ -998,6 +1012,89 @@ func deploymentForDrupalSite(currentobject *appsv1.Deployment, databaseSecret st
 						MountPath: "/var/run/",
 					},
 				}
+			case "sso-proxy":
+				currentobject.Spec.Template.Spec.Containers[i].ImagePullPolicy = "IfNotPresent"
+				currentobject.Spec.Template.Spec.Containers[i].Ports = []corev1.ContainerPort{{
+					ContainerPort: ssoProxyPort,
+					Name:          "sso-proxy",
+					Protocol:      "TCP",
+				}}
+				// Values can be inspired from: https://gitlab.cern.ch/paas-tools/okd4-deployment/cern-auth-proxy/-/blob/master/cern-auth-proxy/templates/deployment.yaml?ref_type=heads
+				currentobject.Spec.Template.Spec.Containers[i].Env = []corev1.EnvVar{
+					{
+						Name:  "OAUTH2_PROXY_HTTP_ADDRESS",
+						Value: ":" + fmt.Sprint(ssoProxyPort),
+					},
+					{
+						Name:  "OAUTH2_PROXY_PROVIDER",
+						Value: "oidc",
+					},
+					{
+						Name:  "OAUTH2_PROXY_SCOPE",
+						Value: "openid",
+					},
+					{
+						Name:  "OAUTH2_PROXY_REVERSE_PROXY",
+						Value: "true",
+					},
+					{
+						Name:  "OAUTH2_PROXY_UPSTREAMS",
+						Value: "http://localhost:8080/",
+					},
+					{
+						Name:  "OAUTH2_PROXY_EMAIL_DOMAINS",
+						Value: "*",
+					},
+					// NOTE: This SSO feature will not work with .cern domains!
+					{
+						Name:  "OAUTH2_PROXY_WHITELIST_DOMAINS",
+						Value: ".cern.ch",
+					},
+					{
+						Name:  "OAUTH2_PROXY_COOKIE_PATH",
+						Value: "/",
+					},
+					{
+						Name:  "OAUTH2_PROXY_SILENCE_PING_LOGGING",
+						Value: "true",
+					},
+					{
+						Name: "OAUTH2_PROXY_CLIENT_ID",
+						ValueFrom: &v1.EnvVarSource{
+							SecretKeyRef: &v1.SecretKeySelector{
+								LocalObjectReference: v1.LocalObjectReference{Name: "oidc-client-secret"},
+								Key:                  "clientID",
+							},
+						},
+					},
+					{
+						Name: "OAUTH2_PROXY_CLIENT_SECRET",
+						ValueFrom: &v1.EnvVarSource{
+							SecretKeyRef: &v1.SecretKeySelector{
+								LocalObjectReference: v1.LocalObjectReference{Name: "oidc-client-secret"},
+								Key:                  "clientSecret",
+							},
+						},
+					},
+					{
+						Name: "OAUTH2_PROXY_OIDC_ISSUER_URL",
+						ValueFrom: &v1.EnvVarSource{
+							SecretKeyRef: &v1.SecretKeySelector{
+								LocalObjectReference: v1.LocalObjectReference{Name: "oidc-client-secret"},
+								Key:                  "issuerURL",
+							},
+						},
+					},
+					{
+						Name: "OAUTH2_PROXY_COOKIE_SECRET",
+						ValueFrom: &v1.EnvVarSource{
+							SecretKeyRef: &v1.SecretKeySelector{
+								LocalObjectReference: v1.LocalObjectReference{Name: "oidc-client-secret"},
+								Key:                  "suggestedCookieSecret",
+							},
+						},
+					},
+				}
 			}
 		}
 	}
@@ -1102,7 +1199,100 @@ func deploymentForDrupalSite(currentobject *appsv1.Deployment, databaseSecret st
 					MountPath: "/var/run/",
 				},
 			}
+
+		case "sso-proxy":
+			currentobject.Spec.Template.Spec.Containers[i].Image = SSOProxyImage
+			// currentobject.Spec.Template.Spec.Containers[i].Command = []string{"sh"}
+			currentobject.Spec.Template.Spec.Containers[i].Resources = config.nginxResources
+			// Set to always due to https://gitlab.cern.ch/drupal/paas/drupalsite-operator/-/issues/54
+			currentobject.Spec.Template.Spec.Containers[i].ImagePullPolicy = "IfNotPresent"
+			currentobject.Spec.Template.Spec.Containers[i].Ports = []corev1.ContainerPort{{
+				ContainerPort: ssoProxyPort,
+				Name:          "sso-proxy",
+				Protocol:      "TCP",
+			}}
+			// Values can be inspired from: https://gitlab.cern.ch/paas-tools/okd4-deployment/cern-auth-proxy/-/blob/master/cern-auth-proxy/templates/deployment.yaml?ref_type=heads
+			currentobject.Spec.Template.Spec.Containers[i].Env = []corev1.EnvVar{
+				{
+					Name:  "OAUTH2_PROXY_HTTP_ADDRESS",
+					Value: ":" + fmt.Sprint(ssoProxyPort),
+				},
+				{
+					Name:  "OAUTH2_PROXY_PROVIDER",
+					Value: "oidc",
+				},
+				{
+					Name:  "OAUTH2_PROXY_SCOPE",
+					Value: "openid",
+				},
+				{
+					Name:  "OAUTH2_PROXY_REVERSE_PROXY",
+					Value: "true",
+				},
+				{
+					Name:  "OAUTH2_PROXY_UPSTREAMS",
+					Value: "http://localhost:8080/",
+				},
+				{
+					Name:  "OAUTH2_PROXY_EMAIL_DOMAINS",
+					Value: "*",
+				},
+				// NOTE: This SSO feature will not work with .cern domains!
+				{
+					Name:  "OAUTH2_PROXY_WHITELIST_DOMAINS",
+					Value: ".cern.ch",
+				},
+				{
+					Name:  "OAUTH2_PROXY_COOKIE_PATH",
+					Value: "/",
+				},
+				{
+					Name:  "OAUTH2_PROXY_SILENCE_PING_LOGGING",
+					Value: "true",
+				},
+				{
+					Name:  "OAUTH2_PROXY_SKIP_PROVIDER_BUTTON",
+					Value: "true",
+				},
+				{
+					Name: "OAUTH2_PROXY_CLIENT_ID",
+					ValueFrom: &v1.EnvVarSource{
+						SecretKeyRef: &v1.SecretKeySelector{
+							LocalObjectReference: v1.LocalObjectReference{Name: "oidc-client-secret"},
+							Key:                  "clientID",
+						},
+					},
+				},
+				{
+					Name: "OAUTH2_PROXY_CLIENT_SECRET",
+					ValueFrom: &v1.EnvVarSource{
+						SecretKeyRef: &v1.SecretKeySelector{
+							LocalObjectReference: v1.LocalObjectReference{Name: "oidc-client-secret"},
+							Key:                  "clientSecret",
+						},
+					},
+				},
+				{
+					Name: "OAUTH2_PROXY_OIDC_ISSUER_URL",
+					ValueFrom: &v1.EnvVarSource{
+						SecretKeyRef: &v1.SecretKeySelector{
+							LocalObjectReference: v1.LocalObjectReference{Name: "oidc-client-secret"},
+							Key:                  "issuerURL",
+						},
+					},
+				},
+				{
+					Name: "OAUTH2_PROXY_COOKIE_SECRET",
+					ValueFrom: &v1.EnvVarSource{
+						SecretKeyRef: &v1.SecretKeySelector{
+							LocalObjectReference: v1.LocalObjectReference{Name: "oidc-client-secret"},
+							Key:                  "suggestedCookieSecret",
+						},
+					},
+				},
+			}
 		}
+
 	}
 	currentobject.Spec.Replicas = &config.replicas
 	// Add an annotation to be able to verify what releaseID of pod is running. Did not use labels, as it will affect the labelselector for the deployment and might cause downtime
@@ -1213,10 +1403,16 @@ func serviceForDrupalSite(currentobject *corev1.Service, d *webservicesv1a1.Drup
 
 	addOwnerRefToObject(currentobject, asOwner(d))
 	currentobject.Spec.Selector = ls
+	serverName := "nginx"
+	serverPort := 8080
+	if d.Labels[ssoProxyLabel] == "true" {
+		serverName = "sso-proxy"
+		serverPort = ssoProxyPort
+	}
 	currentobject.Spec.Ports = []corev1.ServicePort{
 		{
-			TargetPort: intstr.FromInt(8080),
-			Name:       "nginx",
+			TargetPort: intstr.FromInt(serverPort),
+			Name:       serverName,
 			Port:       80,
 			Protocol:   "TCP",
 		},
@@ -1241,10 +1437,13 @@ func routeForDrupalSite(currentobject *routev1.Route, d *webservicesv1a1.DrupalS
 		Name:   d.Name,
 		Weight: pointer.Int32Ptr(100),
 	}
+	port := 8080
+	if d.Labels[ssoProxyLabel] == "true" {
+		port = ssoProxyPort
+	}
 	currentobject.Spec.Port = &routev1.RoutePort{
-		TargetPort: intstr.FromInt(8080),
+		TargetPort: intstr.FromInt(port),
 	}
-
 	if currentobject.Annotations == nil {
 		currentobject.Annotations = map[string]string{}
 	}
@@ -1286,7 +1485,7 @@ func newOidcReturnURI(currentobject *authz.OidcReturnURI, d *webservicesv1a1.Dru
 	}
 
 	// This will append `/openid-connect/*` to the URL, guaranteeing all subpaths of the link can be redirected
-	url.Path = path.Join(url.Path, "openid-connect")
+	//	url.Path = path.Join(url.Path, "openid-connect")
 	if http {
 		returnURI = "http://" + url.String() + "/*" // Hardcoded since with path.Join method creates `%2A` which will not work in the AuthzAPI, and the prefix `http`
 	} else {
diff --git a/controllers/drupalsite_update_controller_utils.go b/controllers/drupalsite_update_controller_utils.go
index 41f39e55dd2e2aac1a44dea2799be783bc3f9411..cac1e74259fc90c1798ca6abe555ae3b88e19ec6 100644
--- a/controllers/drupalsite_update_controller_utils.go
+++ b/controllers/drupalsite_update_controller_utils.go
@@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
-    http://www.apache.org/licenses/LICENSE-2.0
+	http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/controllers/reconciler_common.go b/controllers/reconciler_common.go
index b37a272155fea3e00ddc7d5708ce14ac4ad832db..ab2a65e012f9cb6b482bc556193ae435b918f507 100644
--- a/controllers/reconciler_common.go
+++ b/controllers/reconciler_common.go
@@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
-    http://www.apache.org/licenses/LICENSE-2.0
+	http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
@@ -23,6 +23,7 @@ import (
 	"fmt"
 	"io"
 	"reflect"
+	"slices"
 	"time"
 
 	"github.com/asaskevich/govalidator"
@@ -172,16 +173,17 @@ func ResourceRequestLimit(memReq, cpuReq, memLim, cpuLim string) (corev1.Resourc
 // reqLimDict returns the resource requests and limits for a given QoS class and container.
 // TODO: this should be part of operator configuration, read from a YAML file with format
 // defaultResources:
-//   critical:
-//     phpFpm:
-//       resources:
-//         # normal K8s req/lim
-//     nginx:
-//       # ...
-//   standard:
-//     # ...
-//   eco:
-//     # ...
+//
+//	critical:
+//	  phpFpm:
+//	    resources:
+//	      # normal K8s req/lim
+//	  nginx:
+//	    # ...
+//	standard:
+//	  # ...
+//	eco:
+//	  # ...
 func reqLimDict(container string, qosClass webservicesv1a1.QoSClass) (corev1.ResourceRequirements, error) {
 	switch container {
 	case "php-fpm":
@@ -302,7 +304,7 @@ func addGitlabWebhookToStatus(ctx context.Context, drp *webservicesv1a1.DrupalSi
 	return false
 }
 
-//validateSpec validates the spec against the DrupalSiteSpec definition
+// validateSpec validates the spec against the DrupalSiteSpec definition
 func validateSpec(drpSpec webservicesv1a1.DrupalSiteSpec) reconcileError {
 	_, err := govalidator.ValidateStruct(drpSpec)
 	if err != nil {
@@ -496,6 +498,14 @@ func containerExists(name string, currentobject *appsv1.Deployment) {
 	}
 }
 
+// containerRemove checks if a container exists on the deployment
+// if it does exists, removes it
+func containerRemove(name string, d *appsv1.Deployment) {
+	d.Spec.Template.Spec.Containers = slices.DeleteFunc(d.Spec.Template.Spec.Containers, func(container corev1.Container) bool {
+		return container.Name == name
+	})
+}
+
 // getDeploymentConfiguration precalculates all the configuration that the server deployment needs, including:
 // pod replicas, resource req/lim
 // NOTE: this includes the default resource limits for PHP
@@ -619,12 +629,14 @@ func (r *Reconciler) updateCRStatusOrFailReconcile(ctx context.Context, log logr
 //
 // Example:
 // ````
+//
 //	sout, serr, err := r.execToServerPod(ctx, drp, "php-fpm", nil, "sh", "-c", "drush version; ls")
 //	sout, serr, err := r.execToServerPod(ctx, drp, "php-fpm", nil, "drush", "version")
 //	if err != nil {
 //		log.Error(err, "Error while exec into pod")
 //	}
 //	log.Info("EXEC", "stdout", sout, "stderr", serr)
+//
 // ````
 func (r *Reconciler) execToServerPod(ctx context.Context, d *webservicesv1a1.DrupalSite, containerName string, stdin io.Reader, command ...string) (stdout string, stderr string, err error) {
 	pod, err := r.getRunningPodForVersion(ctx, d, releaseID(d))
diff --git a/main.go b/main.go
index 94892db88e5de520d571a0f9ac9ddbaa82817ca8..617efd3caf431061aa356ce23dc8d3328ecfc35c 100644
--- a/main.go
+++ b/main.go
@@ -79,6 +79,7 @@ func main() {
 	flag.StringVar(&controllers.SiteBuilderImage, "sitebuilder-image", "gitlab-registry.cern.ch/drupal/paas/cern-drupal-distribution/site-builder", "The sitebuilder source image name.")
 	flag.StringVar(&controllers.PhpFpmExporterImage, "php-fpm-exporter-image", "gitlab-registry.cern.ch/drupal/paas/php-fpm-prometheus-exporter:RELEASE.2021.06.02T09-41-38Z", "The php-fpm-exporter source image name.")
 	flag.StringVar(&controllers.WebDAVImage, "webdav-image", "gitlab-registry.cern.ch/drupal/paas/sabredav/webdav:RELEASE-2021.10.12T17-55-06Z", "The webdav source image name.")
+	flag.StringVar(&controllers.SSOProxyImage, "ssoproxy-image", "quay.io/oauth2-proxy/oauth2-proxy:latest", "The sso proxy source image name.") // TODO: Get real image
 	flag.StringVar(&controllers.SMTPHost, "smtp-host", "cernmx.cern.ch", "SMTP host used by Drupal server pods to send emails.")
 	flag.StringVar(&controllers.VeleroNamespace, "velero-namespace", "openshift-cern-drupal", "The namespace of the Velero server to create backups")
 	flag.IntVar(&controllers.ParallelThreadCount, "parallel-thread-count", 1, "The default number of parallel threads executed by the DrupalSite Operator controllers")