diff --git a/roles/keycloak/files/providers/keycloak-mailpass-rest/README.md b/roles/keycloak/files/providers/keycloak-mailpass-rest/README.md
index 73ddfaba9b83e36f3c8d74f3def5e3d1770a91ae..f1b20898d9146c3ee269919ce04dadaf8ce6650f 100644
--- a/roles/keycloak/files/providers/keycloak-mailpass-rest/README.md
+++ b/roles/keycloak/files/providers/keycloak-mailpass-rest/README.md
@@ -42,3 +42,5 @@ docker-compose up -d
 ## Install provider using the Keycloak Deployer
 
 If you copy your provider jar to the Keycloak standalone/deployments/ directory, your provider will automatically be deployed. Hot deployment works too.
+
+Need to add admin role to admin_cli client
diff --git a/roles/keycloak/files/providers/keycloak-mailpass-rest/build.gradle.kts b/roles/keycloak/files/providers/keycloak-mailpass-rest/build.gradle.kts
index 7be43bf263df235937bca3176866752bec278ca2..6e618ce020f1966b7dcf82a98ef18882a0f6f77e 100644
--- a/roles/keycloak/files/providers/keycloak-mailpass-rest/build.gradle.kts
+++ b/roles/keycloak/files/providers/keycloak-mailpass-rest/build.gradle.kts
@@ -16,16 +16,28 @@ repositories {
 }
 
 dependencies {
+    val bouncyCastleVersion = "1.67"
     val keycloakVersion = "11.0.3"
     val javaxVersion = "2.0.1.Final"
-    val bouncyCastleVersion = "1.67"
+    val junitVersion = "4.13.1"
+    val hamcrestVersion = "2.2"
+    val restassuredVersion = "4.3.3"
+    val keycloakMockVersion = "0.6.0"
 
     implementation("org.bouncycastle:bcprov-jdk15on:$bouncyCastleVersion")
 
     compileOnly("org.keycloak:keycloak-core:$keycloakVersion")
     compileOnly("org.keycloak:keycloak-server-spi:$keycloakVersion")
     compileOnly("org.keycloak:keycloak-server-spi-private:$keycloakVersion")
+    compileOnly("org.keycloak:keycloak-services:$keycloakVersion")
+
     compileOnly("org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.1_spec:$javaxVersion")
+
+    testImplementation("junit:junit:$junitVersion")
+    testImplementation("org.hamcrest:hamcrest:$hamcrestVersion")
+    testImplementation("io.rest-assured:rest-assured:$restassuredVersion")
+    testImplementation("com.tngtech.keycloakmock:mock-junit:$keycloakMockVersion")
+
 }
 
 tasks {
@@ -41,4 +53,14 @@ tasks {
     wrapper {
         gradleVersion = "6.7"
     }
+
+    test {
+      useJUnit()
+
+      testLogging {
+        showStandardStreams = true
+    }
+
+      maxHeapSize = "1G"
+    }
 }
diff --git a/roles/keycloak/files/providers/keycloak-mailpass-rest/docker/invoke-authenticated.sh b/roles/keycloak/files/providers/keycloak-mailpass-rest/docker/invoke-authenticated.sh
new file mode 100644
index 0000000000000000000000000000000000000000..56eeda5ffc7b4881b5493c4253e1427a6f70184b
--- /dev/null
+++ b/roles/keycloak/files/providers/keycloak-mailpass-rest/docker/invoke-authenticated.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+export DIRECT_GRANT_RESPONSE=$(curl -i --request POST http://localhost:8080/auth/realms/master/protocol/openid-connect/token --header "Accept: application/json" --header "Content-Type: application/x-www-form-urlencoded" --data "grant_type=password&username=admin&password=admin&client_id=admin-cli")
+
+echo -e "\n\nSENT RESOURCE-OWNER-PASSWORD-CREDENTIALS-REQUEST. OUTPUT IS:\n\n";
+echo $DIRECT_GRANT_RESPONSE;
+
+export ACCESS_TOKEN=$(echo $DIRECT_GRANT_RESPONSE | grep "access_token" | sed 's/.*\"access_token\":\"\([^\"]*\)\".*/\1/g');
+echo -e "\n\nACCESS TOKEN IS \"$ACCESS_TOKEN\"";
+
+echo -e "\n\nSENDING UN-AUTHENTICATED REQUEST. THIS SHOULD FAIL WITH 401: ";
+curl -i --request POST http://localhost:8080/auth/realms/master/mailpass/roleauth/compute-password-hash --data "{ \"pass\": \"password\" }" --header "Content-type: application/json"
+
+echo -e "\n\nSENDING AUTHENTICATED REQUEST. THIS SHOULD SUCCESSFULY CREATE PASSWORD HASH AND SUCCESS WITH 201: ";
+curl -i --request POST http://localhost:8080/auth/realms/master/mailpass/roleauth/compute-password-hash --data "{ \"pass\": \"ompany\" }" --header "Content-type: application/json" --header "Authorization: Bearer $ACCESS_TOKEN";
diff --git a/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassResource.java b/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..8bd06c843b5fbf9138667332f050aa639c95baa5
--- /dev/null
+++ b/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassResource.java
@@ -0,0 +1,71 @@
+package org.archlinux.keycloak.mailpass.rest;
+
+import java.security.SecureRandom;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.bouncycastle.crypto.generators.OpenBSDBCrypt;
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.models.KeycloakSession;
+
+/**
+ * A custom REST endpoint to trigger functionality on the Keycloak server, which is not available
+ * through the default set of built-in Keycloak REST endpoints. This is to be used during the
+ * storage of a custom attribute on the Account Management Console for the mail password. The data
+ * stored will be a Bcrypt hash instead of the plain text password.
+ */
+public class MailPassResource {
+
+
+  @SuppressWarnings("unused")
+  private final KeycloakSession session;
+
+  private static final int SALT_LENGTH = 16;
+  private static final int COST = 12;
+  private static final String VARIANT = "2b";
+
+  private byte[] generateSalt() {
+    // https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#secure-random-number-generation
+    SecureRandom random = new SecureRandom();
+    byte[] salt = new byte[SALT_LENGTH];
+    random.nextBytes(salt);
+    return salt;
+  }
+
+  public MailPassResource(KeycloakSession session) {
+    this.session = session;
+  }
+
+  @GET
+  @Path("hello")
+  @Produces("text/plain; charset=utf-8")
+  public String get() {
+    String name = session.getContext().getRealm().getDisplayName();
+    if (name == null) {
+      name = session.getContext().getRealm().getName();
+    }
+    return "Hello " + name;
+  }
+
+  /**
+   * The custom REST endpoint reachable at {{ base_url }}/realms/{{ realm }}/mailpass/hashify.
+   *
+   * @param data The JSON property including the password entry.
+   * @return Response instance including the hashed password string.
+   */
+  @POST
+  @Path("compute-password-hash")
+  @NoCache
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response generateBcryptHash(String data) {
+
+    byte[] salt = generateSalt();
+    String hash = OpenBSDBCrypt.generate(VARIANT, data.toCharArray(), salt, COST);
+
+    return Response.status(201).entity(hash).build();
+  }
+}
diff --git a/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassResourceProvider.java b/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassResourceProvider.java
index f4af4958f96906f9a0f9c452fc367c88020174b8..18daad81db108980a43d3870faa71237902ffd1f 100644
--- a/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassResourceProvider.java
+++ b/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassResourceProvider.java
@@ -1,66 +1,28 @@
 package org.archlinux.keycloak.mailpass.rest;
 
-import java.security.SecureRandom;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import org.bouncycastle.crypto.generators.OpenBSDBCrypt;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.services.resource.RealmResourceProvider;
 
 /**
- * A custom REST endpoint to trigger functionality on the Keycloak server, which is not available
- * through the default set of built-in Keycloak REST endpoints. This is to be used during the
- * storage of a custom attribute on the Account Management Console for the mail password. The data
- * stored will be a Bcrypt hash instead of the plain text password.
+ * A provider of a custom REST resource for a path relative to Realm's RESTful API
+ * that cannot be resolved by the Keycloak server. This implementation is
+ * a requirement for custom REST endpoints.
  */
 public class MailPassResourceProvider implements RealmResourceProvider {
 
-  private static final int SALT_LENGTH = 16;
-  private static final int COST = 12;
-  private static final String VARIANT = "2b";
-
-  @SuppressWarnings("unused")
   private KeycloakSession session;
 
-  private byte[] generateSalt() {
-    // https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#secure-random-number-generation
-    SecureRandom random = new SecureRandom();
-    byte[] salt = new byte[SALT_LENGTH];
-    random.nextBytes(salt);
-    return salt;
-  }
-
   public MailPassResourceProvider(KeycloakSession session) {
     this.session = session;
   }
 
   @Override
   public Object getResource() {
-    return this;
+    return new MailPassRestResource(session);
   }
 
   @Override
   public void close() {
   }
 
-  /**
-   * The custom REST endpoint reachable at {{ base_url }}/realms/{{ realm }}/mailpass/hashify.
-   *
-   * @param data The JSON property including the password entry.
-   * @return Response instance including the hashed password string.
-   */
-  @POST
-  @Path("compute-password-hash")
-  @Consumes(MediaType.APPLICATION_JSON)
-  public Response generateBcryptHash(String data) {
-
-    byte[] salt = generateSalt();
-    String hash = OpenBSDBCrypt.generate(VARIANT, data.toCharArray(), salt, COST);
-
-    return Response.status(201).entity(hash).build();
-  }
-
 }
diff --git a/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassResourceProviderFactory.java b/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassResourceProviderFactory.java
index 853f0d0a985c9201f57f50c17f740356a8e14cd1..dc39bb25b6523883ed41a1529191282f3bc2622c 100644
--- a/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassResourceProviderFactory.java
+++ b/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassResourceProviderFactory.java
@@ -8,8 +8,7 @@ import org.keycloak.services.resource.RealmResourceProviderFactory;
 
 /**
  * A factory that extends RealmResourceProviderFactory instance to create the custom mail pass
- * resource for a path relative to Realm's RESTful API that cannot be resolved by the Keycloak
- * server. This is a requirement for custom REST endpoints.
+ * resource provider. This implementation is a requirement for custom REST endpoints.
  */
 public class MailPassResourceProviderFactory implements RealmResourceProviderFactory {
 
diff --git a/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassRestResource.java b/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassRestResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..353319c8f04425ae4ea082278658c5b1f39ca6d7
--- /dev/null
+++ b/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/java/org/archlinux/keycloak/mailpass/rest/MailPassRestResource.java
@@ -0,0 +1,46 @@
+package org.archlinux.keycloak.mailpass.rest;
+
+import javax.ws.rs.ForbiddenException;
+import javax.ws.rs.NotAuthorizedException;
+import javax.ws.rs.Path;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.services.managers.AppAuthManager;
+import org.keycloak.services.managers.AuthenticationManager;
+
+/**
+ * A custom REST resource in the form of a domain extension which makes the custom endpoint
+ * accessible just for authenticated users. The REST request must be authenticated with bearer
+ * access token of an authenticated user and the user must be part of a pre-configured realm role in
+ * order to access the resource.
+ */
+public class MailPassRestResource {
+
+  private final KeycloakSession session;
+  private final AuthenticationManager.AuthResult auth;
+
+  public MailPassRestResource(KeycloakSession session) {
+    this.session = session;
+    this.auth = new AppAuthManager().authenticateBearerToken(session);
+  }
+
+  @Path("norole")
+  public MailPassResource getMailPassResource() {
+    return new MailPassResource(session);
+  }
+
+  @Path("roleauth")
+  public MailPassResource getMailPassResourceAuthenticated() {
+    checkRealmAdmin();
+    return new MailPassResource(session);
+  }
+
+  private void checkRealmAdmin() {
+    if (auth == null) {
+      throw new NotAuthorizedException("Bearer");
+    } else if (auth.getToken().getRealmAccess() == null
+        || !auth.getToken().getRealmAccess().isUserInRole("admin")) {
+      throw new ForbiddenException("Does not have realm admin role");
+    }
+  }
+
+}
diff --git a/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/resources/META-INF/jboss-deployment-structure.xml b/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/resources/META-INF/jboss-deployment-structure.xml
index d2577ef12a89e4021ea1c662975bcc83a4c95a76..16268adb63aa3d41b89dd783bd73f04855e154c3 100644
--- a/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/resources/META-INF/jboss-deployment-structure.xml
+++ b/roles/keycloak/files/providers/keycloak-mailpass-rest/src/main/resources/META-INF/jboss-deployment-structure.xml
@@ -1 +1,14 @@
-<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0" />
+<jboss-deployment-structure>
+    <deployment>
+        <dependencies>
+            <module name="org.keycloak.keycloak-core" />
+            <module name="org.keycloak.keycloak-server-spi" />
+            <module name="org.jboss.resteasy.resteasy-jaxrs" />
+            <module name="org.keycloak.keycloak-server-spi-private" />
+            <module name="org.keycloak.keycloak-services" />
+            <module name="org.keycloak.keycloak-common" />
+            <module name="org.jboss.logging" />
+            <module name="javax.ws.rs.api" />
+        </dependencies>
+    </deployment>
+</jboss-deployment-structure>