diff --git a/app/adapters/web/pom.xml b/app/adapters/web/pom.xml
index eb73c15..d33c739 100644
--- a/app/adapters/web/pom.xml
+++ b/app/adapters/web/pom.xml
@@ -31,13 +31,17 @@
     </dependency>
 
     <dependency>
-      <groupId>jakarta.faces</groupId>
-      <artifactId>jakarta.faces-api</artifactId>
+      <groupId>jakarta.enterprise</groupId>
+      <artifactId>jakarta.enterprise.cdi-api</artifactId>
       <scope>provided</scope>
     </dependency>
     <dependency>
-      <groupId>jakarta.enterprise</groupId>
-      <artifactId>jakarta.enterprise.cdi-api</artifactId>
+      <groupId>jakarta.el</groupId>
+      <artifactId>jakarta.el-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>jakarta.faces</groupId>
+      <artifactId>jakarta.faces-api</artifactId>
       <scope>provided</scope>
     </dependency>
     <dependency>
@@ -45,6 +49,17 @@
       <artifactId>jakarta.inject-api</artifactId>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>jakarta.security.enterprise</groupId>
+      <artifactId>jakarta.security.enterprise-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>jakarta.servlet</groupId>
+      <artifactId>jakarta.servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
     <dependency>
       <groupId>org.primefaces</groupId>
       <artifactId>primefaces</artifactId>
diff --git a/app/adapters/web/src/main/java/it/mulders/traqqr/web/security/OidcConfig.java b/app/adapters/web/src/main/java/it/mulders/traqqr/web/security/OidcConfig.java
new file mode 100644
index 0000000..417abfb
--- /dev/null
+++ b/app/adapters/web/src/main/java/it/mulders/traqqr/web/security/OidcConfig.java
@@ -0,0 +1,25 @@
+package it.mulders.traqqr.web.security;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Named;
+
+@ApplicationScoped
+@Named("oidcConfig")
+public class OidcConfig {
+    private final String clientId;
+    private final String clientSecret;
+
+    public OidcConfig() {
+        var environment = System.getenv();
+        this.clientId = environment.get("OPENID_CLIENT_ID");
+        this.clientSecret = environment.get("OPENID_CLIENT_SECRET");
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public String getClientSecret() {
+        return clientSecret;
+    }
+}
diff --git a/app/adapters/web/src/main/java/it/mulders/traqqr/web/security/SecurityConfiguration.java b/app/adapters/web/src/main/java/it/mulders/traqqr/web/security/SecurityConfiguration.java
new file mode 100644
index 0000000..7dd650c
--- /dev/null
+++ b/app/adapters/web/src/main/java/it/mulders/traqqr/web/security/SecurityConfiguration.java
@@ -0,0 +1,23 @@
+package it.mulders.traqqr.web.security;
+
+import jakarta.security.enterprise.authentication.mechanism.http.OpenIdAuthenticationMechanismDefinition;
+import jakarta.security.enterprise.authentication.mechanism.http.openid.ClaimsDefinition;
+import jakarta.security.enterprise.authentication.mechanism.http.openid.LogoutDefinition;
+
+@OpenIdAuthenticationMechanismDefinition(
+        claimsDefinition = @ClaimsDefinition(
+                callerNameClaim = "sub"
+        ),
+        clientId = "${oidcConfig.clientId}",
+        clientSecret = "${oidcConfig.clientSecret}",
+        logout = @LogoutDefinition(
+                redirectURI = "${baseURL}"
+        ),
+        providerURI = "https://accounts.google.com/.well-known/openid-configuration",
+        redirectURI = "${baseURL}/auth/callback/google",
+        redirectToOriginalResource = true,
+        useNonce = true,
+        useSession = true
+)
+public class SecurityConfiguration {
+}
diff --git a/app/adapters/web/src/main/java/it/mulders/traqqr/web/security/TraqqrIdentityStore.java b/app/adapters/web/src/main/java/it/mulders/traqqr/web/security/TraqqrIdentityStore.java
new file mode 100644
index 0000000..ca386bc
--- /dev/null
+++ b/app/adapters/web/src/main/java/it/mulders/traqqr/web/security/TraqqrIdentityStore.java
@@ -0,0 +1,26 @@
+package it.mulders.traqqr.web.security;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.security.enterprise.identitystore.CredentialValidationResult;
+import jakarta.security.enterprise.identitystore.IdentityStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+@ApplicationScoped
+public class TraqqrIdentityStore implements IdentityStore {
+    private static final Logger log = LoggerFactory.getLogger(TraqqrIdentityStore.class);
+
+    @Override
+    public Set<String> getCallerGroups(final CredentialValidationResult validationResult) {
+        log.info("Assigning groups; caller_unique_id={}", validationResult.getCallerUniqueId());
+        return Set.of("user");
+    }
+
+    @Override
+    public Set<ValidationType> validationTypes() {
+        return EnumSet.of(ValidationType.PROVIDE_GROUPS);
+    }
+}
diff --git a/app/adapters/web/src/main/java/it/mulders/traqqr/web/user/UserInfoBean.java b/app/adapters/web/src/main/java/it/mulders/traqqr/web/user/UserInfoBean.java
new file mode 100644
index 0000000..4cd67c0
--- /dev/null
+++ b/app/adapters/web/src/main/java/it/mulders/traqqr/web/user/UserInfoBean.java
@@ -0,0 +1,32 @@
+package it.mulders.traqqr.web.user;
+
+import jakarta.enterprise.context.SessionScoped;
+import jakarta.inject.Inject;
+import jakarta.inject.Named;
+import jakarta.security.enterprise.SecurityContext;
+import jakarta.security.enterprise.identitystore.openid.OpenIdContext;
+
+import java.io.Serializable;
+
+@Named
+@SessionScoped
+public class UserInfoBean implements Serializable {
+    private final String displayName;
+    private final String profilePictureUrl;
+
+    @Inject
+    public UserInfoBean(final SecurityContext securityContext,
+                        final OpenIdContext openIdContext) {
+        var claims = openIdContext.getClaims();
+        this.displayName = claims.getName().orElse("unknown user");
+        this.profilePictureUrl = claims.getPicture().orElse(null);
+    }
+
+    public String getUsername() {// name, picture, email
+        return displayName;
+    }
+
+    public String getProfilePictureUrl() {
+        return profilePictureUrl;
+    }
+}
diff --git a/app/adapters/web/src/main/webapp/META-INF/beans.xml b/app/adapters/web/src/main/webapp/META-INF/beans.xml
new file mode 100644
index 0000000..e7ca12d
--- /dev/null
+++ b/app/adapters/web/src/main/webapp/META-INF/beans.xml
@@ -0,0 +1,5 @@
+<beans xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd"
+       version="4.0"
+       bean-discovery-mode="all">
+</beans>
\ No newline at end of file
diff --git a/app/adapters/web/src/main/webapp/WEB-INF/layout-closed.xhtml b/app/adapters/web/src/main/webapp/WEB-INF/layout-closed.xhtml
new file mode 100644
index 0000000..d5fa0e4
--- /dev/null
+++ b/app/adapters/web/src/main/webapp/WEB-INF/layout-closed.xhtml
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:h="http://xmlns.jcp.org/jsf/html"
+      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
+      xmlns:p="http://primefaces.org/ui">
+<h:head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <title><ui:insert name="title">Default Title</ui:insert> | Traqqr</title>
+</h:head>
+<body>
+<ui:debug/>
+
+<div class="content">
+    <ui:insert name="content"/>
+</div>
+
+<hr />
+<!-- alleen als ingelogd -->
+<p:outputPanel>
+    Traqqr ${systemInfo.applicationVersion} (revision <code>${systemInfo.gitVersion}</code>) is made with ❤️ + ☕ + <a href="https://dev.java/" target="_blank">Java ${systemInfo.javaVersion}</a> + <a href="https://jakarta.ee/" target="_blank">Jakarta EE 10</a>.
+    Proudly running on ${systemInfo.javaRuntime}.
+</p:outputPanel>
+</body>
+</html>
\ No newline at end of file
diff --git a/app/adapters/web/src/main/webapp/WEB-INF/layout.xhtml b/app/adapters/web/src/main/webapp/WEB-INF/layout-open.xhtml
similarity index 82%
rename from app/adapters/web/src/main/webapp/WEB-INF/layout.xhtml
rename to app/adapters/web/src/main/webapp/WEB-INF/layout-open.xhtml
index 6100599..a491252 100644
--- a/app/adapters/web/src/main/webapp/WEB-INF/layout.xhtml
+++ b/app/adapters/web/src/main/webapp/WEB-INF/layout-open.xhtml
@@ -1,7 +1,8 @@
 <!DOCTYPE html>
 <html xmlns="http://www.w3.org/1999/xhtml"
       xmlns:h="http://xmlns.jcp.org/jsf/html"
-      xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
+      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
+      xmlns:p="http://primefaces.org/ui">
     <h:head>
         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
         <title><ui:insert name="title">Default Title</ui:insert> | Traqqr</title>
diff --git a/app/adapters/web/src/main/webapp/WEB-INF/web.xml b/app/adapters/web/src/main/webapp/WEB-INF/web.xml
index d6e45fc..e58578b 100644
--- a/app/adapters/web/src/main/webapp/WEB-INF/web.xml
+++ b/app/adapters/web/src/main/webapp/WEB-INF/web.xml
@@ -24,6 +24,23 @@
         <url-pattern>*.xhtml</url-pattern>
     </servlet-mapping>
 
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Traqqr</web-resource-name>
+            <url-pattern>/secure/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+        <user-data-constraint>
+            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+        </user-data-constraint>
+    </security-constraint>
+
     <!-- Primefaces configuration -->
     <context-param>
         <param-name>primefaces.CLIENT_SIDE_VALIDATION</param-name>
diff --git a/app/adapters/web/src/main/webapp/index.xhtml b/app/adapters/web/src/main/webapp/index.xhtml
index e8c906a..04f6ec0 100644
--- a/app/adapters/web/src/main/webapp/index.xhtml
+++ b/app/adapters/web/src/main/webapp/index.xhtml
@@ -3,7 +3,7 @@
         xmlns:f="http://xmlns.jcp.org/jsf/core"
         xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
         xmlns:p="http://primefaces.org/ui"
-        template="/WEB-INF/layout.xhtml">
+        template="/WEB-INF/layout-open.xhtml">
     <ui:define name="title">Start</ui:define>
 
     <ui:define name="content">
diff --git a/app/adapters/web/src/main/webapp/privacy.xhtml b/app/adapters/web/src/main/webapp/privacy.xhtml
index c889c9a..d4873fc 100644
--- a/app/adapters/web/src/main/webapp/privacy.xhtml
+++ b/app/adapters/web/src/main/webapp/privacy.xhtml
@@ -2,7 +2,7 @@
         xmlns="http://www.w3.org/1999/xhtml"
         xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
         xmlns:p="http://primefaces.org/ui"
-        template="/WEB-INF/layout.xhtml">
+        template="/WEB-INF/layout-open.xhtml">
    <ui:define name="title">Privacy</ui:define>
 
    <ui:define name="content">
diff --git a/app/adapters/web/src/main/webapp/secure/index.xhtml b/app/adapters/web/src/main/webapp/secure/index.xhtml
new file mode 100644
index 0000000..710bfe0
--- /dev/null
+++ b/app/adapters/web/src/main/webapp/secure/index.xhtml
@@ -0,0 +1,16 @@
+<ui:composition
+        xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:f="http://xmlns.jcp.org/jsf/core"
+        xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
+        xmlns:p="http://primefaces.org/ui"
+        template="/WEB-INF/layout-closed.xhtml">
+    <ui:define name="title">Start</ui:define>
+
+    <ui:define name="content">
+        <p:card>
+            <f:facet name="title">Secure Dashboard</f:facet>
+
+            <p>Hi ${userInfoBean.username}!</p>
+        </p:card>
+    </ui:define>
+</ui:composition>
diff --git a/runtime/src/main/liberty/config/google-client-keystore.p12 b/runtime/src/main/liberty/config/google-client-keystore.p12
new file mode 100644
index 0000000..1a47a4e
Binary files /dev/null and b/runtime/src/main/liberty/config/google-client-keystore.p12 differ
diff --git a/runtime/src/main/liberty/config/server.xml b/runtime/src/main/liberty/config/server.xml
index d45b153..65adb33 100644
--- a/runtime/src/main/liberty/config/server.xml
+++ b/runtime/src/main/liberty/config/server.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <server description="traqqr-dev-server">
     <featureManager>
+        <feature>appSecurity-5.0</feature>
         <feature>beanValidation-3.0</feature>
         <feature>cdi-4.0</feature>
         <feature>expressionLanguage-5.0</feature>
@@ -12,7 +13,7 @@
 
     <application location="traqqr.ear" name="traqqr" contextRoot="/" />
 
-    <!-- Enable detailed logging for JPA.
+    <!-- Enable detailed logging for Jakarta Persistence API.
     <logging traceSpecification="eclipselink=all:eclipselink.sql=all" />
      -->
     <!-- Enable detailed logging for Jakarta Security. -->