You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2021/06/10 10:42:38 UTC

[isis] branch master updated: ISIS-2727: remove Authentication from 'security'

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new e93e59d  ISIS-2727: remove Authentication from 'security'
e93e59d is described below

commit e93e59ddbffbc6337f62e90f1bdc17389cc4d24c
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Jun 10 12:42:21 2021 +0200

    ISIS-2727: remove Authentication from 'security'
    
    instead have UserMemento hold the authentication state
    
    also adds some todos
---
 .../services/iactnlayer/InteractionContext.java    |  70 ++------
 .../isis/applib/services/user/UserMemento.java     | 195 ++++++++++-----------
 .../applib/services/user/UserMemento_Test.java     |  40 ++---
 .../interaction/integration/IsisRequestCycle.java  |  20 +--
 .../interaction/session/InteractionFactory.java    |  38 ++--
 .../interaction/session/InteractionTracker.java    |  38 ++--
 .../_testing/MetaModelContext_forTesting.java      |  16 +-
 .../metamodel/interactions/InteractionContext.java |   7 +-
 .../metamodel/facets/AbstractFacetFactoryTest.java |   8 +-
 .../actions/ActionMethodsFacetFactoryTest.java     |   5 +-
 .../TitleAnnotationFacetFactoryTest.java           |  26 ++-
 .../NavigableParentAnnotationFacetFactoryTest.java |  15 +-
 .../runtimeservices/clock/ClockServiceDefault.java |   2 +-
 .../session/AnonymousAuthentication.java           |  37 ----
 .../session/InteractionFactoryDefault.java         |  55 +++---
 .../runtimeservices/sudo/SudoServiceDefault.java   |  11 +-
 .../runtimeservices/user/UserServiceDefault.java   |   4 +-
 .../wrapper/WrapperFactoryDefault.java             |  17 +-
 .../security/authentication/Authentication.java    | 123 -------------
 .../authentication/AuthenticationAbstract.java     |  90 +---------
 .../authentication/AuthenticationProvider.java     |   7 +-
 .../authentication/AuthenticationRequest.java      |   8 +-
 .../security/authentication/Authenticator.java     |  12 +-
 .../authentication/InteractionContextFactory.java  |  74 ++++++++
 .../health/HealthAuthentication.java               |  41 -----
 .../security/authentication/logout/LogoutMenu.java |  11 +-
 .../manager/AuthenticationManager.java             |  22 ++-
 .../singleuser/SingleUserAuthentication.java       |  44 -----
 .../standard/AuthenticatorAbstract.java            |  13 +-
 .../standard/SimpleAuthentication.java             |  64 -------
 .../core/security/authorization/Authorizor.java    |  12 +-
 .../manager/AuthorizationManager.java              |   8 +-
 .../isis/security/EncodabilityContractTest.java    |  17 +-
 .../SimpleSessionEncodabilityNoRolesTest.java      |   7 +-
 .../SimpleSessionEncodabilityTestAbstract.java     |  19 +-
 .../SimpleSessionEncodabilityWithRolesTest.java    |   8 +-
 ...rdAuthenticationManager_AuthenticationTest.java |  12 +-
 .../HealthIndicatorUsingHealthCheckService.java    |  10 +-
 .../secondary/job/ReplicateAndReplayJob.java       |  13 +-
 .../secman/applib/user/dom/ApplicationUser.java    |   6 +-
 .../authenticator/AuthenticatorSecman.java         |  10 +-
 .../integration/authorizor/AuthorizorSecman.java   |  12 +-
 .../vaadin/ui/auth/AuthSessionStoreUtil.java       |  22 +--
 .../viewer/vaadin/ui/auth/LogoutHandlerVaa.java    |   2 +-
 .../ui/auth/VaadinAuthenticationHandler.java       |   6 +-
 .../viewer/vaadin/viewer/IsisServletForVaadin.java |   3 +-
 .../testing/AbstractFacetFactoryTest.java          |  10 +-
 .../bypass/authorization/AuthorizorBypass.java     |   6 +-
 .../authentication/AuthenticatorKeycloak.java      |   8 +-
 .../keycloak/webmodule/KeycloakFilter.java         |  19 +-
 .../shiro/authentication/AuthenticatorShiro.java   |  12 +-
 .../shiro/authorization/AuthorizorShiro.java       |  10 +-
 ...AuthenticatorOrAuthorizorTest_authenticate.java |  11 +-
 ...ticatorOrAuthorizorTest_isVisibleInAnyRole.java |   7 +-
 .../spring/authentication/AuthenticatorSpring.java |   6 +-
 .../spring/webmodule/SpringSecurityFilter.java     |  22 +--
 ..._ensureCompatibleAcceptHeader_ContractTest.java |  14 +-
 .../viewer/resources/HomePageReprRenderer.java     |   4 +-
 .../viewer/resources/UserReprRenderer.java         |   8 +-
 .../IsisRestfulObjectsInteractionFilter.java       |   8 +-
 .../webmodule/auth/AuthenticationStrategy.java     |  14 +-
 .../auth/AuthenticationStrategyAbstract.java       |   3 +-
 .../auth/AuthenticationStrategyBasicAuth.java      |   8 +-
 .../auth/AuthenticationStrategyDefault.java        |  15 +-
 .../context/ResourceContext_getArg_Test.java       |   8 +-
 .../AuthenticatedWebSessionForIsis.java            |  23 +--
 ...uthenticatedWebSessionForIsis_Authenticate.java |  22 +--
 .../AuthenticatedWebSessionForIsis_SignIn.java     |  18 +-
 ...uthenticatedWebSessionForIsis_TestAbstract.java |   8 +-
 69 files changed, 573 insertions(+), 971 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/iactnlayer/InteractionContext.java b/api/applib/src/main/java/org/apache/isis/applib/services/iactnlayer/InteractionContext.java
index f27b3f5..394de8f 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/iactnlayer/InteractionContext.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/iactnlayer/InteractionContext.java
@@ -19,23 +19,17 @@
 package org.apache.isis.applib.services.iactnlayer;
 
 import java.io.Serializable;
-import java.util.HashMap;
 import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
 import java.util.TimeZone;
 
 import org.apache.isis.applib.clock.VirtualClock;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.user.UserMemento;
-import org.apache.isis.commons.internal.base._Casts;
 
 import lombok.Builder;
 import lombok.Getter;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
-import lombok.Value;
 import lombok.With;
 
 /**
@@ -43,12 +37,28 @@ import lombok.With;
  *
  * @since 2.0 {@index}
  */
-@Value @Builder
+@lombok.Value @Builder
 @RequiredArgsConstructor
 public class InteractionContext implements Serializable {
 
     private static final long serialVersionUID = -220896735209733865L;
 
+    // -- FACTORIES
+
+    /**
+     * Creates a new {@link InteractionContext} with the specified user and
+     * system defaults for clock, locale and time-zone.
+     */
+    public static InteractionContext ofUserWithSystemDefaults(
+            final @NonNull UserMemento user) {
+        return InteractionContext.builder()
+                .user(user)
+                .clock(VirtualClock.system())
+                .locale(Locale.getDefault())
+                .timeZone(TimeZone.getDefault())
+                .build();
+    }
+
     // -- IMMUTABLE FIELDS
 
     /**
@@ -75,53 +85,7 @@ public class InteractionContext implements Serializable {
     @With @Getter @Builder.Default
     @NonNull TimeZone timeZone = TimeZone.getDefault();
 
-    Map<String, Serializable> attributes = new HashMap<>();
-    public void putAttribute(String key, Serializable value) {
-        attributes.put(key, value);
-    }
 
-    public <T> Optional<T> getAttribute(String key, Class<T> castTo) {
-        return _Casts.castTo(attributes.get(key), castTo);
-    }
-
-
-    // -- EQUALS and HASHCODE
-
-    /**
-     * We exclude {@link #attributes}.
-     */
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-        InteractionContext that = (InteractionContext) o;
-        return user.equals(that.user) && clock.equals(that.clock) && locale.equals(that.locale) && timeZone.equals(that.timeZone);
-    }
-
-    /**
-     * We exclude {@link #attributes}.
-     */
-    @Override
-    public int hashCode() {
-        return Objects.hash(user, clock, locale, timeZone);
-    }
-
-
-    // -- FACTORIES
-
-    /**
-     * Creates a new {@link InteractionContext} with the specified user and
-     * system defaults for clock, locale and time-zone.
-     */
-    public static InteractionContext ofUserWithSystemDefaults(
-            final @NonNull UserMemento user) {
-        return InteractionContext.builder()
-                .user(user)
-                .clock(VirtualClock.system())
-                .locale(Locale.getDefault())
-                .timeZone(TimeZone.getDefault())
-                .build();
-    }
 
 
 }
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java b/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java
index 97ce853a..1b3213a 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java
@@ -20,14 +20,13 @@ package org.apache.isis.applib.services.user;
 
 import java.io.Serializable;
 import java.net.URL;
-import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import javax.annotation.Nullable;
 
+import org.springframework.boot.autoconfigure.neo4j.Neo4jProperties.Authentication;
+
 import org.apache.isis.applib.IsisModuleApplib;
 import org.apache.isis.applib.annotation.Collection;
 import org.apache.isis.applib.annotation.CollectionLayout;
@@ -36,12 +35,13 @@ import org.apache.isis.applib.annotation.Optionality;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.annotation.Property;
 import org.apache.isis.applib.annotation.PropertyLayout;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Strings;
-import org.apache.isis.commons.internal.collections._Lists;
 
+import lombok.Builder;
 import lombok.Getter;
 import lombok.NonNull;
-import lombok.val;
+import lombok.With;
 
 /**
  * Immutable serializable value holding details about a user and its roles.
@@ -49,6 +49,7 @@ import lombok.val;
  * @since 1.x revised for 2.0 {@index}
  */
 @DomainObject(logicalTypeName = UserMemento.LOGICAL_TYPE_NAME)
+@lombok.Value @lombok.Builder
 public final class UserMemento implements Serializable {
 
     public static final String LOGICAL_TYPE_NAME = IsisModuleApplib.NAMESPACE + ".UserMemento";
@@ -65,13 +66,15 @@ public final class UserMemento implements Serializable {
         return SYSTEM_USER;
     }
 
-
     /**
      * Creates a new user with the specified name and no roles.
      */
     public static UserMemento ofName(
             final @NonNull String name) {
-        return new UserMemento(name, Stream.empty());
+
+        return builderWithDefaults(name)
+                .roles(Can.empty())
+                .build();
     }
 
     /**
@@ -80,7 +83,10 @@ public final class UserMemento implements Serializable {
     public static UserMemento ofNameAndRoles(
             final @NonNull String name,
             final RoleMemento... roles) {
-        return new UserMemento(name, Stream.of(roles));
+
+        return builderWithDefaults(name)
+                .roles(Can.ofArray(roles))
+                .build();
     }
 
     /**
@@ -107,103 +113,61 @@ public final class UserMemento implements Serializable {
     public static UserMemento ofNameAndRoleNames(
             final @NonNull String name,
             final @NonNull Stream<String> roleNames) {
-        return new UserMemento(name, roleNames.map(RoleMemento::new));
-    }
-
-    // -- CONSTRUCTOR
 
-    /**
-     * Creates a new user with the specified name and assigned roles.
-     */
-    public UserMemento(final String name, final @NonNull Stream<RoleMemento> roles) {
-        if (_Strings.isEmpty(name)) {
-            throw new IllegalArgumentException("Name not specified");
-        }
-        this.name = name;
-        this.roles = roles.collect(_Lists.toUnmodifiable());
+        return builderWithDefaults(name)
+                .roles(roleNames
+                        .map(RoleMemento::new)
+                        .collect(Can.toCan()))
+                .build();
     }
 
+    // -- UI TITLE
+
     public String title() {
         return name;
     }
 
+    // -- PROPERTIES
+
     /**
      * The user's login name.
      */
     @Property
     @PropertyLayout(sequence = "1.1")
     @Getter
-    private final String name;
+    private final @NonNull String name;
 
     @Property(optionality = Optionality.OPTIONAL)
     @PropertyLayout(sequence = "1.2")
-    @Getter
-    private String realName;
-
-    @Programmatic
-    public UserMemento withRealName(final String realName) {
-        val userMemento = copy();
-        userMemento.realName = realName;
-        return userMemento;
-    }
+    @Getter @With(onMethod_ = {@Programmatic})
+    private final @Nullable String realName;
 
     @Property(optionality = Optionality.OPTIONAL)
     @PropertyLayout(sequence = "1.3")
-    @Getter
-    @Nullable
-    private URL avatarUrl;
-
-    @Programmatic
-    public UserMemento withAvatarUrl(final URL avatarUrl) {
-        val userMemento = copy();
-        userMemento.avatarUrl = avatarUrl;
-        return userMemento;
-    }
+    @Getter @With(onMethod_ = {@Programmatic})
+    private final @Nullable URL avatarUrl;
 
     @Property(optionality = Optionality.OPTIONAL)
     @PropertyLayout(sequence = "1.4")
-    @Getter
-    private boolean impersonating;
-
-    public UserMemento withImpersonating() {
-        final UserMemento copy = copy();
-        copy.impersonating = true;
-        return copy;
-    }
-
-    private UserMemento copy() {
-        return copy(this.roles);
-    }
-
-    private UserMemento copy(final List<RoleMemento> roles) {
-        val userMemento = new UserMemento(this.name, roles.stream());
-        userMemento.realName = this.realName;
-        userMemento.avatarUrl = this.avatarUrl;
-        userMemento.impersonating = this.impersonating;
-        return userMemento;
-    }
-
+    @Getter @Builder.Default @With(onMethod_ = {@Programmatic})
+    private final boolean impersonating = false;
 
     /**
      * The roles associated with this user.
      */
     @Collection
     @CollectionLayout(sequence = "1.4")
-    private final List<RoleMemento> roles;
-    public List<RoleMemento> getRoles() {
-        return roles;
-    }
+    @Getter @Builder.Default
+    private final Can<RoleMemento> roles = Can.empty();
+
 
     @Programmatic
-    public UserMemento withRole(String role) {
-        final List<RoleMemento> roles = new ArrayList<>(this.roles);
-        roles.add(new RoleMemento(role));
-        val userMemento = copy(roles);
-        return userMemento;
+    public UserMemento withRoleAdded(String role) {
+        return asBuilder()
+        .roles(roles.add(new RoleMemento(role)))
+        .build();
     }
 
-
-
     /**
      * Determine if the specified name is this user.
      *
@@ -226,40 +190,69 @@ public final class UserMemento implements Serializable {
         return streamRoleNames().anyMatch(myRoleName->myRoleName.equals(roleName));
     }
 
-    // -- TO STRING, EQUALS, HASHCODE
+    // -- AUTHENTICATION
 
-    @Override
-    public String toString() {
-        val rolesStringified = roles.stream()
-        .map(RoleMemento::getName)
-        .collect(Collectors.joining(", "));
-        return "User [name=" + getName() + ", roles=" + rolesStringified + "]";
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == this) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (obj.getClass() != getClass()) {
-            return false;
+    /**
+     * To support external security mechanisms such as keycloak,
+     * where the validity of the session is defined by headers in the request.
+     */
+    @Property
+    @PropertyLayout(sequence = "2.0")
+    @Getter @Builder.Default @With(onMethod_ = {@Programmatic})
+    private final @NonNull AuthenticationSource authenticationSource = AuthenticationSource.DEFAULT;
+
+    public enum AuthenticationSource {
+        DEFAULT,
+        /**
+         * Instructs the {@link org.apache.isis.core.security.authentication.manager.AuthenticationManager} to not cache this session in its internal map of
+         * sessions by validation code, and therefore to ignore this aspect when considering if an
+         * {@link Authentication} is
+         * {@link org.apache.isis.core.security.authentication.manager.AuthenticationManager#isSessionValid(Authentication) valid} or not.
+         */
+        EXTERNAL;
+
+        public boolean isExternal() {
+            return this == EXTERNAL;
         }
-        return isEqualsTo((UserMemento) obj);
     }
 
-    private boolean isEqualsTo(final UserMemento other) {
-        if(!Objects.equals(this.getName(), other.getName())) {
-            return false;
-        }
-        return Objects.equals(this.getRoles(), other.getRoles());
+    /**
+     * A unique code given to this user during authentication.
+     * <p>
+     * This can be used to confirm that the user has been authenticated.
+     * It should return an empty string {@literal ""}
+     * if this is an anonymous (unauthenticated) user.
+     */
+    @Property
+    @PropertyLayout(sequence = "2.1")
+    @Getter @Builder.Default @With(onMethod_ = {@Programmatic})
+    private final @NonNull String authenticationCode = "";
+
+
+    // -- UTILITY
+
+    @Programmatic
+    public UserMementoBuilder asBuilder() {
+        //XXX update whenever new fields are added
+        return UserMemento.builder()
+                .name(name)
+                .authenticationCode(authenticationCode)
+                .authenticationSource(authenticationSource)
+                .avatarUrl(avatarUrl)
+                .impersonating(impersonating)
+                .realName(realName)
+                .roles(roles);
     }
 
-    @Override
-    public int hashCode() {
-        return getName().hashCode(); // its good enough to hash on just the user's name
+    // -- HELPER
+
+    private static UserMementoBuilder builderWithDefaults(final String name) {
+        if (_Strings.isEmpty(name)) {
+            throw new IllegalArgumentException("Name not specified");
+        }
+        // actually using @Builder.Default on the fields to set builder defaults
+        return UserMemento.builder()
+                .name(name);
     }
 
 
diff --git a/api/applib/src/test/java/org/apache/isis/applib/services/user/UserMemento_Test.java b/api/applib/src/test/java/org/apache/isis/applib/services/user/UserMemento_Test.java
index 3ddf609..504ac66 100644
--- a/api/applib/src/test/java/org/apache/isis/applib/services/user/UserMemento_Test.java
+++ b/api/applib/src/test/java/org/apache/isis/applib/services/user/UserMemento_Test.java
@@ -21,7 +21,7 @@ class UserMemento_Test {
 
             // then original unchanged
             Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento.getRoles()).hasSize(0);
+            Assertions.assertThat(userMemento.getRoles().size()).isEqualTo(0);
             Assertions.assertThat(userMemento.getRealName()).isNull();
             Assertions.assertThat(userMemento.getAvatarUrl()).isNull();
         }
@@ -34,7 +34,7 @@ class UserMemento_Test {
 
             // then
             Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+            Assertions.assertThat(userMemento.getRoles().size()).isEqualTo(2);
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
             Assertions.assertThat(userMemento.getRealName()).isNull();
@@ -58,14 +58,14 @@ class UserMemento_Test {
 
             // then copy correct
             Assertions.assertThat(userMemento2.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento2.getRoles()).hasSize(2);
+            Assertions.assertThat(userMemento2.getRoles().size()).isEqualTo(2);
             Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
             Assertions.assertThat(userMemento2.getRealName()).isEqualTo("Fred Flintstone");
 
             // then original unchanged
             Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+            Assertions.assertThat(userMemento.getRoles().size()).isEqualTo(2);
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
             Assertions.assertThat(userMemento.getRealName()).isNull();
@@ -85,7 +85,7 @@ class UserMemento_Test {
 
             // then copy correct
             Assertions.assertThat(userMemento2.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento2.getRoles()).hasSize(2);
+            Assertions.assertThat(userMemento2.getRoles().size()).isEqualTo(2);
             Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
             Assertions.assertThat(userMemento2.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
@@ -93,7 +93,7 @@ class UserMemento_Test {
 
             // then original unchanged
             Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+            Assertions.assertThat(userMemento.getRoles().size()).isEqualTo(2);
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
             Assertions.assertThat(userMemento.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
@@ -118,14 +118,14 @@ class UserMemento_Test {
 
             // then copy correct
             Assertions.assertThat(userMemento2.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento2.getRoles()).hasSize(2);
+            Assertions.assertThat(userMemento2.getRoles().size()).isEqualTo(2);
             Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
             Assertions.assertThat(userMemento2.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
 
             // then original unchanged
             Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+            Assertions.assertThat(userMemento.getRoles().size()).isEqualTo(2);
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
             Assertions.assertThat(userMemento.getAvatarUrl()).isNull();
@@ -145,7 +145,7 @@ class UserMemento_Test {
 
             // then copy correct
             Assertions.assertThat(userMemento2.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento2.getRoles()).hasSize(2);
+            Assertions.assertThat(userMemento2.getRoles().size()).isEqualTo(2);
             Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
             Assertions.assertThat(userMemento2.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
@@ -153,7 +153,7 @@ class UserMemento_Test {
 
             // then original unchanged
             Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+            Assertions.assertThat(userMemento.getRoles().size()).isEqualTo(2);
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
             Assertions.assertThat(userMemento.getRealName()).isEqualTo("Fred Flintstone");
@@ -171,21 +171,21 @@ class UserMemento_Test {
             val userMemento = UserMemento.ofNameAndRoleNames("fredflintstone", "CAVEMAN", "HUSBAND");
 
             // when
-            val userMemento2 = userMemento.withRole("WICKET_ROLE");
+            val userMemento2 = userMemento.withRoleAdded("WICKET_ROLE");
 
             // then copy created
             Assertions.assertThat(userMemento2).isNotSameAs(userMemento);
 
             // then copy correct
             Assertions.assertThat(userMemento2.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento2.getRoles()).hasSize(3);
+            Assertions.assertThat(userMemento2.getRoles().size()).isEqualTo(3);
             Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
             Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("WICKET_ROLE"));
 
             // then original unchanged
             Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+            Assertions.assertThat(userMemento.getRoles().size()).isEqualTo(2);
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
         }
@@ -201,7 +201,7 @@ class UserMemento_Test {
             val userMemento = UserMemento.ofNameAndRoleNames("fredflintstone", "CAVEMAN", "HUSBAND");
 
             // when
-            val userMemento2 = userMemento.withImpersonating();
+            val userMemento2 = userMemento.withImpersonating(true);
 
             // then copy created
             Assertions.assertThat(userMemento2).isNotSameAs(userMemento);
@@ -222,14 +222,14 @@ class UserMemento_Test {
 
             // when
             val userMemento = UserMemento.ofName("fredflintstone")
-                    .withRole("CAVEMAN")
-                    .withRole("HUSBAND")
+                    .withRoleAdded("CAVEMAN")
+                    .withRoleAdded("HUSBAND")
                     .withAvatarUrl(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"))
                     .withRealName("Fred Flintstone");
 
             // then
             Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+            Assertions.assertThat(userMemento.getRoles().size()).isEqualTo(2);
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
             Assertions.assertThat(userMemento.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
@@ -237,14 +237,14 @@ class UserMemento_Test {
             Assertions.assertThat(userMemento.isImpersonating()).isFalse();
 
             // and when
-            val userMemento2 = userMemento.withImpersonating();
+            val userMemento2 = userMemento.withImpersonating(true);
 
             // then copy created
             Assertions.assertThat(userMemento2).isNotSameAs(userMemento);
 
             // then copy correct
             Assertions.assertThat(userMemento2.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento2.getRoles()).hasSize(2);
+            Assertions.assertThat(userMemento2.getRoles().size()).isEqualTo(2);
             Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
             Assertions.assertThat(userMemento2.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
@@ -253,7 +253,7 @@ class UserMemento_Test {
 
             // then original unchanged
             Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
-            Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+            Assertions.assertThat(userMemento.getRoles().size()).isEqualTo(2);
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
             Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
             Assertions.assertThat(userMemento.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
diff --git a/core/interaction/src/main/java/org/apache/isis/core/interaction/integration/IsisRequestCycle.java b/core/interaction/src/main/java/org/apache/isis/core/interaction/integration/IsisRequestCycle.java
index c84716c..ed90701 100644
--- a/core/interaction/src/main/java/org/apache/isis/core/interaction/integration/IsisRequestCycle.java
+++ b/core/interaction/src/main/java/org/apache/isis/core/interaction/integration/IsisRequestCycle.java
@@ -18,10 +18,10 @@
  */
 package org.apache.isis.core.interaction.integration;
 
-import org.apache.isis.applib.services.user.ImpersonatedUserHolder;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.iactnlayer.InteractionService;
-import org.apache.isis.core.security.authentication.Authentication;
-import org.apache.isis.core.security.authentication.standard.SimpleAuthentication;
+import org.apache.isis.applib.services.user.ImpersonatedUserHolder;
+import org.apache.isis.core.security.authentication.InteractionContextFactory;
 
 import lombok.RequiredArgsConstructor;
 import lombok.val;
@@ -38,16 +38,16 @@ public class IsisRequestCycle {
 
     // -- SUPPORTING WEB REQUEST CYCLE FOR ISIS ...
 
-    public void onBeginRequest(final Authentication authentication) {
+    public void onBeginRequest(final InteractionContext authenticatedContext) {
 
-        val authenticationToUse = impersonatedUserHolder.getUserMemento()
-                .<Authentication>map(impersonatingUserMemento->
-                    SimpleAuthentication.of(
+        val contextToUse = impersonatedUserHolder.getUserMemento()
+                .<InteractionContext>map(impersonatingUserMemento->
+                    InteractionContextFactory.valid(
                         impersonatingUserMemento,
-                        authentication.getValidationCode()))
-                .orElse(authentication);
+                        authenticatedContext.getUser().getAuthenticationCode()))
+                .orElse(authenticatedContext);
 
-        interactionService.openInteraction(authenticationToUse.getInteractionContext());
+        interactionService.openInteraction(contextToUse);
     }
 
     public void onRequestHandlerExecuted() {
diff --git a/core/interaction/src/main/java/org/apache/isis/core/interaction/session/InteractionFactory.java b/core/interaction/src/main/java/org/apache/isis/core/interaction/session/InteractionFactory.java
index c332933..14f220d 100644
--- a/core/interaction/src/main/java/org/apache/isis/core/interaction/session/InteractionFactory.java
+++ b/core/interaction/src/main/java/org/apache/isis/core/interaction/session/InteractionFactory.java
@@ -25,13 +25,12 @@ import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.iactnlayer.InteractionLayer;
 import org.apache.isis.applib.services.iactnlayer.InteractionService;
 import org.apache.isis.applib.services.iactnlayer.ThrowingRunnable;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.manager.AnonymousInteractionFactory;
 
 import lombok.NonNull;
 
 /**
- * The factory of {@link Authentication}(s) and {@link InteractionLayer}(s),
+ * The factory of {@link InteractionLayer}(s),
  * holding a reference to the current
  * {@link InteractionLayer authentication layer} stack using
  * a thread-local.
@@ -45,31 +44,32 @@ import lombok.NonNull;
 public interface InteractionFactory
 extends AnonymousInteractionFactory, InteractionService {
 
-    /**
-     * As per {@link #call(InteractionContext, Callable)}, using the {@link InteractionContext}
-     * {@link Authentication#getInteractionContext() obtained} from the provided {@link Authentication}.
-     *
-     * @param authentication - the user details to run under (non-null)
-     * @param callable - the piece of code to run (non-null)
-     */
-    <R> R callAuthenticated(@NonNull Authentication authentication, @NonNull Callable<R> callable);
+//    /**
+//     * As per {@link #call(InteractionContext, Callable)}, using the {@link InteractionContext}
+//     * {@link Authentication#getInteractionContext() obtained} from the provided {@link Authentication}.
+//     *
+//     * @param authentication - the user details to run under (non-null)
+//     * @param callable - the piece of code to run (non-null)
+//     */
+//    <R> R callAuthenticated(@NonNull Authentication authentication, @NonNull Callable<R> callable);
 
     /**
-     * As per {@link #call(InteractionContext, Callable)}, but using an {@link InteractionContext}
-     * {@link Authentication#getInteractionContext() obtained} from an anonymous {@link Authentication}.
+     * As per {@link #call(InteractionContext, Callable)}, but using an
+     * anonymous {@link InteractionContext}.
      *
      * @param <R>
      * @param callable (non-null)
      */
+    @Override
     <R> R callAnonymous(@NonNull Callable<R> callable);
 
-    /**
-     * As per {@link #callAuthenticated(Authentication, Callable)}, but for a runnable.
-     *
-     * @param authentication - the user details to run under (non-null)
-     * @param runnable (non-null)
-     */
-    void runAuthenticated(@NonNull Authentication authentication, @NonNull ThrowingRunnable runnable);
+//    /**
+//     * As per {@link #callAuthenticated(Authentication, Callable)}, but for a runnable.
+//     *
+//     * @param authentication - the user details to run under (non-null)
+//     * @param runnable (non-null)
+//     */
+//    void runAuthenticated(@NonNull Authentication authentication, @NonNull ThrowingRunnable runnable);
 
     /**
      * As per {@link #callAnonymous(Callable)}, but for a runnable.
diff --git a/core/interaction/src/main/java/org/apache/isis/core/interaction/session/InteractionTracker.java b/core/interaction/src/main/java/org/apache/isis/core/interaction/session/InteractionTracker.java
index ca92551..6562803 100644
--- a/core/interaction/src/main/java/org/apache/isis/core/interaction/session/InteractionTracker.java
+++ b/core/interaction/src/main/java/org/apache/isis/core/interaction/session/InteractionTracker.java
@@ -20,12 +20,11 @@ package org.apache.isis.core.interaction.session;
 
 import java.util.Optional;
 
-import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.iactn.InteractionProvider;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.iactnlayer.InteractionLayer;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.AuthenticationProvider;
 
 /**
@@ -41,48 +40,33 @@ extends InteractionProvider, AuthenticationProvider {
 
     default InteractionLayer currentInteractionLayerElseFail() {
         return currentInteractionLayer()
-        .orElseThrow(()->_Exceptions.illegalState("No InteractionLayer available on current thread"));
-    }
-
-    /**
-     * Returns the {@link InteractionContext} wrapped by the {@link #currentInteractionLayer()} (if within an interaction layer).
-     */
-    default Optional<InteractionContext> currentExecutionContext() {
-        return currentInteractionLayer().map(InteractionLayer::getInteractionContext);
-    }
-
-
-    // -- AUTHENTICATION
-
-    /**
-     * Returns the {@link Authentication} wrapped by the {@link #currentInteractionLayer()} (if within an interaction layer).
-     */
-    @Override
-    default Optional<Authentication> currentAuthentication() {
-        return currentInteractionLayer()
-                .map(InteractionLayer::getInteractionContext)
-                .flatMap(Authentication::authenticationFrom);
+                .orElseThrow(()->_Exceptions
+                        .illegalState("No InteractionLayer available on current thread"));
     }
 
     // -- INTERACTION CONTEXT
 
     /**
-     * Returns the {@link InteractionContext} wrapped by the {@link #currentInteractionLayer()} (if within an interaction layer).
+     * Returns the {@link InteractionContext} wrapped by the {@link #currentInteractionLayer()}
+     * (if within an interaction layer).
      */
     @Override
     default Optional<InteractionContext> currentInteractionContext() {
-        return currentInteractionLayer().map(InteractionLayer::getInteractionContext);
+        return currentInteractionLayer()
+                .map(InteractionLayer::getInteractionContext);
     }
 
 
     // -- INTERACTION
 
     /**
-     * Returns the {@link Interaction} wrapped by the {@link #currentInteractionLayer()} (if within an interaction layer).
+     * Returns the {@link Interaction} wrapped by the {@link #currentInteractionLayer()}
+     * (if within an interaction layer).
      */
     @Override
     default Optional<Interaction> currentInteraction(){
-    	return currentInteractionLayer().map(InteractionLayer::getInteraction);
+    	return currentInteractionLayer()
+    	        .map(InteractionLayer::getInteraction);
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/MetaModelContext_forTesting.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/MetaModelContext_forTesting.java
index abbe373..8fb347d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/MetaModelContext_forTesting.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/MetaModelContext_forTesting.java
@@ -23,10 +23,13 @@ import java.util.Map;
 import java.util.function.Consumer;
 import java.util.stream.Stream;
 
+import static java.util.Objects.requireNonNull;
+
 import org.springframework.core.env.AbstractEnvironment;
 
 import org.apache.isis.applib.services.factory.FactoryService;
 import org.apache.isis.applib.services.i18n.TranslationService;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.applib.services.repository.RepositoryService;
@@ -53,13 +56,10 @@ import org.apache.isis.core.metamodel.services.events.MetamodelEventService;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoaderDefault;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.AuthenticationProvider;
 import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
 import org.apache.isis.core.security.authorization.manager.AuthorizationManager;
 
-import static java.util.Objects.requireNonNull;
-
 import lombok.Builder;
 import lombok.Getter;
 import lombok.Singular;
@@ -99,7 +99,7 @@ public final class MetaModelContext_forTesting implements MetaModelContext {
 
     private TranslationService translationService;
 
-    private Authentication authentication;
+    private InteractionContext authentication;
 
     private AuthorizationManager authorizationManager;
 
@@ -200,7 +200,7 @@ public final class MetaModelContext_forTesting implements MetaModelContext {
     @Override
     public ServiceRegistry getServiceRegistry() {
         if(serviceRegistry==null) {
-            serviceRegistry = new ServiceRegistry_forTesting((MetaModelContext)this);
+            serviceRegistry = new ServiceRegistry_forTesting(this);
         }
         return serviceRegistry;
     }
@@ -208,7 +208,7 @@ public final class MetaModelContext_forTesting implements MetaModelContext {
     @Override
     public ServiceInjector getServiceInjector() {
         if(serviceInjector==null) {
-            serviceInjector = new ServiceInjector_forTesting((MetaModelContext)this);
+            serviceInjector = new ServiceInjector_forTesting(this);
         }
         return serviceInjector;
     }
@@ -216,7 +216,7 @@ public final class MetaModelContext_forTesting implements MetaModelContext {
     @Override
     public FactoryService getFactoryService() {
         if(factoryService==null) {
-            factoryService = new FactoryService_forTesting((MetaModelContext)this);
+            factoryService = new FactoryService_forTesting(this);
         }
         return factoryService;
     }
@@ -281,7 +281,7 @@ public final class MetaModelContext_forTesting implements MetaModelContext {
     @Override
     public ObjectManager getObjectManager() {
         if(objectManager==null) {
-            objectManager = ObjectManagerDefault.forTesting((MetaModelContext)this);
+            objectManager = ObjectManagerDefault.forTesting(this);
         }
         return objectManager;
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/InteractionContext.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/InteractionContext.java
index 22ee2cc..1e8ec49 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/InteractionContext.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/InteractionContext.java
@@ -26,7 +26,6 @@ import org.apache.isis.core.metamodel.consent.InteractionContextType;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.security.authentication.Authentication;
 
 import lombok.Getter;
 
@@ -37,7 +36,8 @@ import lombok.Getter;
  * <p>
  * There are two main responsibilities:
  * <ul>
- * <li>Wraps up a target object, parameters and a {@link Authentication}.
+ * <li>Wraps up a target object, parameters and a
+ * {@link org.apache.isis.applib.services.iactnlayer.InteractionContext}.
  * Defining this as a separate interface makes for a more stable API</li>
  * <li>Acts as a factory for the corresponding {@link InteractionEvent} (more on
  * this below).</li>
@@ -48,7 +48,8 @@ import lombok.Getter;
  * {@link InteractionEvent} hierarchy. Having parallel hierarchies is a bit of a
  * code-smell. However, it is required because the {@link InteractionContext
  * context} hierarchy is internal to the framework (with references to
- * {@link ManagedObject}s, {@link Authentication}s and so forth), whereas
+ * {@link ManagedObject}s,
+ * {@link org.apache.isis.applib.services.iactnlayer.InteractionContext}s and so forth), whereas
  * the {@link InteractionEvent event} hierarchy is part of AppLib, that is
  * public API.
  *
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/AbstractFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/AbstractFacetFactoryTest.java
index 4f0cde5..d376e4b 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/AbstractFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/AbstractFacetFactoryTest.java
@@ -28,6 +28,7 @@ import org.junit.Rule;
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.i18n.TranslationService;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.commons.collections.ImmutableEnumSet;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
@@ -43,8 +44,8 @@ import org.apache.isis.core.metamodel.facets.collections.layout.CollectionLayout
 import org.apache.isis.core.metamodel.facets.properties.propertylayout.PropertyLayoutFacetFactory;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.AuthenticationProvider;
+import org.apache.isis.core.security.authentication.InteractionContextFactory;
 
 import junit.framework.TestCase;
 
@@ -68,7 +69,7 @@ public abstract class AbstractFacetFactoryTest extends TestCase {
 
     protected TranslationService mockTranslationService;
     protected AuthenticationProvider mockAuthenticationProvider;
-    protected Authentication mockAuthentication;
+    protected final InteractionContext iaContext = InteractionContextFactory.testing();
     protected SpecificationLoader mockSpecificationLoader;
     protected MethodRemoverForTesting methodRemover;
 
@@ -109,7 +110,6 @@ public abstract class AbstractFacetFactoryTest extends TestCase {
         mockAuthenticationProvider = context.mock(AuthenticationProvider.class);
 
         mockTranslationService = context.mock(TranslationService.class);
-        mockAuthentication = context.mock(Authentication.class);
 
         mockSpecificationLoader = context.mock(SpecificationLoader.class);
 
@@ -122,7 +122,7 @@ public abstract class AbstractFacetFactoryTest extends TestCase {
         context.checking(new Expectations() {{
 
             allowing(mockAuthenticationProvider).currentAuthentication();
-            will(returnValue(Optional.of(mockAuthentication)));
+            will(returnValue(Optional.of(iaContext)));
         }});
 
         ((MetaModelContextAware)facetHolder).setMetaModelContext(metaModelContext);
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/ActionMethodsFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/ActionMethodsFacetFactoryTest.java
index 8206473..064f069 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/ActionMethodsFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/ActionMethodsFacetFactoryTest.java
@@ -54,7 +54,6 @@ import org.apache.isis.core.metamodel.facets.param.defaults.methodnum.ActionPara
 import org.apache.isis.core.metamodel.facets.param.defaults.methodnum.ActionParameterDefaultsFacetViaMethodFactory;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.testspec.ObjectSpecificationStub;
-import org.apache.isis.core.security.authentication.Authentication;
 
 import lombok.val;
 
@@ -73,12 +72,10 @@ public class ActionMethodsFacetFactoryTest extends AbstractFacetFactoryTest {
 
         super.setUp();
 
-        final Authentication mockAuthentication = context.mock(Authentication.class);
-
         context.checking(new Expectations() {{
 
             allowing(mockAuthenticationProvider).currentAuthentication();
-            will(returnValue(Optional.of(mockAuthentication)));
+            will(returnValue(Optional.of(iaContext)));
         }});
 
     }
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/title/annotation/TitleAnnotationFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/title/annotation/TitleAnnotationFacetFactoryTest.java
index 05e8df1..6e8a10b 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/title/annotation/TitleAnnotationFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/title/annotation/TitleAnnotationFacetFactoryTest.java
@@ -31,7 +31,11 @@ import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
 import org.apache.isis.applib.annotation.Title;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facets.AbstractFacetFactoryJUnit4TestCase;
 import org.apache.isis.core.metamodel.facets.Annotations;
@@ -40,20 +44,16 @@ import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
 import org.apache.isis.core.metamodel.facets.object.title.annotation.TitleAnnotationFacetFactory;
 import org.apache.isis.core.metamodel.facets.object.title.annotation.TitleFacetViaTitleAnnotation;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.AuthenticationProvider;
+import org.apache.isis.core.security.authentication.InteractionContextFactory;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-public class TitleAnnotationFacetFactoryTest extends AbstractFacetFactoryJUnit4TestCase {
+public class TitleAnnotationFacetFactoryTest
+extends AbstractFacetFactoryJUnit4TestCase {
 
     private TitleAnnotationFacetFactory facetFactory;
 
-    @Mock
-    private ManagedObject mockObjectAdapter;
-    @Mock
-    private Authentication mockAuthentication;
+    @Mock private ManagedObject mockObjectAdapter;
+    protected final InteractionContext iaContext = InteractionContextFactory.testing();
 
     @Before
     public void setUp() throws Exception {
@@ -70,13 +70,7 @@ public class TitleAnnotationFacetFactoryTest extends AbstractFacetFactoryJUnit4T
                 will(returnValue(Optional.of(mockAuthenticationTracker)));
 
                 allowing(mockAuthenticationTracker).currentAuthentication();
-                will(returnValue(Optional.of(mockAuthentication)));
-
-                //                allowing(mockServicesInjector).getSpecificationLoader();
-                //                will(returnValue(mockSpecificationLoader));
-                //
-                //                allowing(mockServicesInjector).getPersistenceSessionServiceInternal();
-                //                will(returnValue(mockPersistenceSessionServiceInternal));
+                will(returnValue(Optional.of(iaContext)));
             }
         });
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/navparent/annotation/NavigableParentAnnotationFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/navparent/annotation/NavigableParentAnnotationFacetFactoryTest.java
index 7e30568..c35a80a 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/navparent/annotation/NavigableParentAnnotationFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/navparent/annotation/NavigableParentAnnotationFacetFactoryTest.java
@@ -28,6 +28,7 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.commons.internal._Constants;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facets.AbstractFacetFactoryJUnit4TestCase;
@@ -36,17 +37,17 @@ import org.apache.isis.core.metamodel.facets.object.navparent.NavigableParentFac
 import org.apache.isis.core.metamodel.facets.object.navparent.annotation.NavigableParentTestSamples.DomainObjectA;
 import org.apache.isis.core.metamodel.facets.object.navparent.method.NavigableParentFacetMethod;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.AuthenticationProvider;
+import org.apache.isis.core.security.authentication.InteractionContextFactory;
 
-public class NavigableParentAnnotationFacetFactoryTest extends AbstractFacetFactoryJUnit4TestCase {
+public class NavigableParentAnnotationFacetFactoryTest
+extends AbstractFacetFactoryJUnit4TestCase {
 
     private NavigableParentAnnotationFacetFactory facetFactory;
 
-    @Mock
-    private ManagedObject mockObjectAdapter;
-    @Mock
-    private Authentication mockAuthentication;
+    @Mock private ManagedObject mockObjectAdapter;
+
+    private final InteractionContext iaContext = InteractionContextFactory.testing();
 
     @Before
     public void setUp() throws Exception {
@@ -63,7 +64,7 @@ public class NavigableParentAnnotationFacetFactoryTest extends AbstractFacetFact
                 will(returnValue(Optional.of(mockAuthenticationTracker)));
 
                 allowing(mockAuthenticationTracker).currentAuthentication();
-                will(returnValue(Optional.of(mockAuthentication)));
+                will(returnValue(Optional.of(iaContext)));
 
                 //                allowing(mockServicesInjector).getSpecificationLoader();
                 //                will(returnValue(mockSpecificationLoader));
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/clock/ClockServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/clock/ClockServiceDefault.java
index b9fa7bc..aa20237 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/clock/ClockServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/clock/ClockServiceDefault.java
@@ -46,7 +46,7 @@ public class ClockServiceDefault implements ClockService {
 
     @Override
     public VirtualClock getClock() {
-        return interactionTracker.currentExecutionContext()
+        return interactionTracker.currentInteractionContext()
         .map(InteractionContext::getClock)
         .orElseGet(VirtualClock::system);
     }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/AnonymousAuthentication.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/AnonymousAuthentication.java
deleted file mode 100644
index ee55816..0000000
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/AnonymousAuthentication.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you 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
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.core.runtimeservices.session;
-
-import org.apache.isis.applib.services.iactnlayer.InteractionContext;
-import org.apache.isis.applib.services.user.UserMemento;
-import org.apache.isis.core.security.authentication.AuthenticationAbstract;
-
-public final class AnonymousAuthentication extends AuthenticationAbstract {
-
-    private static final long serialVersionUID = 1L;
-
-    private static final InteractionContext INITIALISATION_CONTEXT =
-            InteractionContext.ofUserWithSystemDefaults(UserMemento.system());
-
-    public AnonymousAuthentication() {
-        super(INITIALISATION_CONTEXT, AuthenticationAbstract.DEFAULT_AUTH_VALID_CODE);
-    }
-
-
-}
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionFactoryDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionFactoryDefault.java
index 8e8c55e..91038ea 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionFactoryDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionFactoryDefault.java
@@ -19,8 +19,6 @@
 
 package org.apache.isis.core.runtimeservices.session;
 
-import static org.apache.isis.commons.internal.base._With.requires;
-
 import java.io.File;
 import java.sql.Timestamp;
 import java.util.List;
@@ -46,11 +44,12 @@ import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.iactnlayer.InteractionContext;
+import org.apache.isis.applib.services.iactnlayer.InteractionLayer;
+import org.apache.isis.applib.services.iactnlayer.ThrowingRunnable;
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.applib.util.schema.ChangesDtoUtils;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
 import org.apache.isis.applib.util.schema.InteractionDtoUtils;
-import org.apache.isis.applib.services.iactnlayer.ThrowingRunnable;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.concurrent._ConcurrentContext;
 import org.apache.isis.commons.internal.concurrent._ConcurrentTaskList;
@@ -61,16 +60,17 @@ import org.apache.isis.core.interaction.integration.InteractionAwareTransactiona
 import org.apache.isis.core.interaction.scope.InteractionScopeAware;
 import org.apache.isis.core.interaction.scope.InteractionScopeBeanFactoryPostProcessor;
 import org.apache.isis.core.interaction.scope.InteractionScopeLifecycleHandler;
-import org.apache.isis.applib.services.iactnlayer.InteractionLayer;
 import org.apache.isis.core.interaction.session.InteractionFactory;
 import org.apache.isis.core.interaction.session.InteractionTracker;
 import org.apache.isis.core.interaction.session.IsisInteraction;
 import org.apache.isis.core.metamodel.services.publishing.CommandPublisher;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.runtime.events.MetamodelEventService;
-import org.apache.isis.core.security.authentication.Authentication;
+import org.apache.isis.core.security.authentication.InteractionContextFactory;
 import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
 
+import static org.apache.isis.commons.internal.base._With.requires;
+
 import lombok.NonNull;
 import lombok.SneakyThrows;
 import lombok.val;
@@ -160,10 +160,7 @@ implements
     public InteractionLayer openInteraction() {
         return currentInteractionLayer()
                 // or else create an anonymous authentication layer
-                .orElseGet(()-> {
-                    final AnonymousAuthentication authToUse = new AnonymousAuthentication();
-                    return openInteraction(authToUse.getInteractionContext());
-                });
+                .orElseGet(()->openInteraction(InteractionContextFactory.anonymous()));
     }
 
     @Override
@@ -255,14 +252,14 @@ implements
     }
 
 
-    @Override
-    @SneakyThrows
-    public <R> R callAuthenticated(
-            @NonNull final Authentication authentication,
-            @NonNull final Callable<R> callable) {
-
-        return call(authentication.getInteractionContext(), callable);
-    }
+//    @Override
+//    @SneakyThrows
+//    public <R> R callAuthenticated(
+//            @NonNull final Authentication authentication,
+//            @NonNull final Callable<R> callable) {
+//
+//        return call(authentication.getInteractionContext(), callable);
+//    }
 
     @Override
     @SneakyThrows
@@ -279,14 +276,14 @@ implements
 
     }
 
-    @Override
-    @SneakyThrows
-    public void runAuthenticated(
-            @NonNull final Authentication authentication,
-            @NonNull final ThrowingRunnable runnable) {
-
-        run(authentication.getInteractionContext(), runnable);
-    }
+//    @Override
+//    @SneakyThrows
+//    public void runAuthenticated(
+//            @NonNull final Authentication authentication,
+//            @NonNull final ThrowingRunnable runnable) {
+//
+//        run(authentication.getInteractionContext(), runnable);
+//    }
 
 
     // -- ANONYMOUS EXECUTION
@@ -298,7 +295,7 @@ implements
             serviceInjector.injectServicesInto(callable);
             return callable.call(); // reuse existing session
         }
-        return callAuthenticated(new AnonymousAuthentication(), callable);
+        return call(InteractionContextFactory.anonymous(), callable);
     }
 
     /**
@@ -313,7 +310,7 @@ implements
             runnable.run(); // reuse existing session
             return;
         }
-        runAuthenticated(new AnonymousAuthentication(), runnable);
+        run(InteractionContextFactory.anonymous(), runnable);
     }
 
     // -- CONVERSATION ID
@@ -414,5 +411,9 @@ implements
         interaction.clear();
     }
 
+    @Override
+    public Optional<InteractionContext> currentAuthentication() {
+        return currentInteractionContext();
+    }
 
 }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/sudo/SudoServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/sudo/SudoServiceDefault.java
index bf02c91..b976bf7 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/sudo/SudoServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/sudo/SudoServiceDefault.java
@@ -19,7 +19,6 @@
 
 package org.apache.isis.core.runtimeservices.sudo;
 
-import java.util.Optional;
 import java.util.concurrent.Callable;
 import java.util.function.UnaryOperator;
 
@@ -39,9 +38,6 @@ import org.apache.isis.applib.services.sudo.SudoServiceListener;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.interaction.session.InteractionFactory;
 import org.apache.isis.core.interaction.session.InteractionTracker;
-import org.apache.isis.core.runtimeservices.session.AnonymousAuthentication;
-import org.apache.isis.core.security.authentication.Authentication;
-import org.apache.isis.core.security.authentication.standard.SimpleAuthentication;
 
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
@@ -80,14 +76,11 @@ public class SudoServiceDefault implements SudoService {
         val currentInteractionContext = currentInteractionLayer.getInteractionContext();
         val sudoInteractionContext = sudoMapper.apply(currentInteractionContext);
 
-        val authentication = Authentication.authenticationFrom(currentInteractionContext)
-                                .orElse(SimpleAuthentication.validOf(currentInteractionContext));
-        val sudoAuthentication = authentication.withInteractionContext(sudoInteractionContext);
-
         try {
             beforeCall(currentInteractionContext, sudoInteractionContext);
 
-            return interactionFactory.callAuthenticated(sudoAuthentication, callable);
+            return interactionFactory
+                    .call(sudoInteractionContext, callable);
         } finally {
             afterCall(sudoInteractionContext, currentInteractionContext);
         }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/user/UserServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/user/UserServiceDefault.java
index a09ef90..82b8ede 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/user/UserServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/user/UserServiceDefault.java
@@ -62,7 +62,7 @@ public class UserServiceDefault implements UserService {
         Optional<UserMemento> optional = getImpersonatedUser();
         return optional.isPresent()
                 ? optional
-                : isisInteractionTracker.currentExecutionContext().map(InteractionContext::getUser);
+                : isisInteractionTracker.currentInteractionContext().map(InteractionContext::getUser);
     }
 
     @Override
@@ -82,7 +82,7 @@ public class UserServiceDefault implements UserService {
         impersonatingHolder().ifPresent(x ->
                 {
                     val userMemento = UserMemento.ofNameAndRoleNames(userName, roles)
-                                        .withImpersonating();
+                                        .withImpersonating(true);
                     x.setUserMemento(userMemento);
                 }
         );
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java
index 48dacb6..5a52903 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java
@@ -47,8 +47,9 @@ import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandExecutorService;
 import org.apache.isis.applib.services.factory.FactoryService;
-import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.iactn.InteractionProvider;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
+import org.apache.isis.applib.services.iactnlayer.InteractionLayer;
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.applib.services.metamodel.MetaModelService;
 import org.apache.isis.applib.services.repository.RepositoryService;
@@ -81,7 +82,6 @@ import org.apache.isis.commons.collections.ImmutableEnumSet;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.commons.internal.proxy._ProxyFactoryService;
-import org.apache.isis.applib.services.iactnlayer.InteractionLayer;
 import org.apache.isis.core.interaction.session.InteractionFactory;
 import org.apache.isis.core.interaction.session.InteractionTracker;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
@@ -101,7 +101,6 @@ import org.apache.isis.core.runtimeservices.wrapper.dispatchers.InteractionEvent
 import org.apache.isis.core.runtimeservices.wrapper.handlers.DomainObjectInvocationHandler;
 import org.apache.isis.core.runtimeservices.wrapper.handlers.ProxyContextHandler;
 import org.apache.isis.core.runtimeservices.wrapper.proxy.ProxyCreator;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
 import static org.apache.isis.applib.services.metamodel.MetaModelService.Mode.RELAXED;
@@ -361,14 +360,6 @@ public class WrapperFactoryDefault implements WrapperFactory {
         val interactionContext = interactionLayer.getInteractionContext();
         val asyncInteractionContext = interactionContextFrom(asyncControl, interactionContext);
 
-        val authIfAny = Authentication.authenticationFrom(interactionLayer.getInteractionContext());
-        if(!authIfAny.isPresent()) {
-            return null;
-        }
-
-        val auth = authIfAny.get();
-        val asyncAuth = auth.withInteractionContext(asyncInteractionContext);
-
         val command = interactionProviderProvider.get().currentInteractionElseFail().getCommand();
         val commandInteractionId = command.getInteractionId();
 
@@ -402,7 +393,6 @@ public class WrapperFactoryDefault implements WrapperFactory {
         val executorService = asyncControl.getExecutorService();
         val future = executorService.submit(
                 new ExecCommand<R>(
-                        asyncAuth,
                         asyncInteractionContext,
                         Propagation.REQUIRES_NEW,
                         commandDto,
@@ -591,7 +581,6 @@ public class WrapperFactoryDefault implements WrapperFactory {
     @RequiredArgsConstructor
     private static class ExecCommand<R> implements Callable<R> {
 
-        private final Authentication authentication;
         private final InteractionContext interactionContext;
         private final Propagation propagation;
         private final CommandDto commandDto;
@@ -610,7 +599,7 @@ public class WrapperFactoryDefault implements WrapperFactory {
         @Override
         public R call() {
             serviceInjector.injectServicesInto(this);
-            return interactionFactory.callAuthenticated(authentication, this::updateDomainObjectHonoringTransactionalPropagation);
+            return interactionFactory.call(interactionContext, this::updateDomainObjectHonoringTransactionalPropagation);
         }
 
         private R updateDomainObjectHonoringTransactionalPropagation() {
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/Authentication.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/Authentication.java
deleted file mode 100644
index ef52626..0000000
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/Authentication.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you 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
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.isis.core.security.authentication;
-
-import java.io.Serializable;
-import java.util.Optional;
-
-import org.apache.isis.applib.services.iactn.Interaction;
-import org.apache.isis.applib.services.iactnlayer.InteractionContext;
-import org.apache.isis.applib.services.user.UserMemento;
-
-import lombok.NonNull;
-
-/**
- * An immutable, serializable value type, that holds details about a user's authentication.
- *
- * <p>
- *     This is really little more than a thin wrapper around {@link InteractionContext},
- *     surfaces a number of the security-specific attributes of that field.
- * </p>
- *
- * @apiNote This is a framework internal class and so does not constitute a formal API.
- *
- * @since 2.0 {@index}
- */
-public interface Authentication extends Serializable {
-
-    String INTERACTION_CONTEXT_KEY = Authentication.class.getName();
-
-    /**
-     * The name of the authenticated user; for display purposes only.
-     */
-    default String getUserName() {
-        return getUser().getName();
-    }
-
-    /**
-     * A unique code given to this session during authentication.
-     *
-     * <p>
-     * This can be used to confirm that this session has been properly created
-     * and the user has been authenticated. It should return an empty string (
-     * <tt>""</tt>) if this is unauthenticated user
-     */
-    String getValidationCode();
-
-    /**
-     * The (programmatically) simulated (or actual) user, belonging to this session.
-     *
-     * @apiNote immutable, allows an {@link Interaction} to (logically) run with its
-     * own simulated (or actual) user
-     */
-    default UserMemento getUser() {
-        return getInteractionContext().getUser();
-    }
-
-    /**
-     * The {@link InteractionContext} (programmatically) simulated (or actual), belonging to this session.
-     *
-     * @apiNote immutable, allows an {@link Interaction} to (logically) run with its
-     * own simulated (or actual) clock
-     */
-    InteractionContext getInteractionContext();
-
-    /**
-     * To support external security mechanisms such as keycloak, where the validity of the session is defined by
-     * headers in the request.
-     */
-    default Type getType() {
-        return Type.DEFAULT;
-    }
-
-    public enum Type {
-        DEFAULT,
-        /**
-         * Instructs the {@link org.apache.isis.core.security.authentication.manager.AuthenticationManager} to not cache this session in its internal map of
-         * sessions by validation code, and therefore to ignore this aspect when considering if an
-         * {@link Authentication} is
-         * {@link org.apache.isis.core.security.authentication.manager.AuthenticationManager#isSessionValid(Authentication) valid} or not.
-         */
-        EXTERNAL
-    }
-
-    // -- WITHERS
-
-    /**
-     * Returns a copy with given {@code interactionContext}.
-     * @param interactionContext
-     */
-    Authentication withInteractionContext(InteractionContext interactionContext);
-
-    /**
-     * Looks up an {@link Authentication} from the provided {@link InteractionContext}.
-     *
-     * <p>
-     *     If the {@link InteractionContext} was created as the result of an authentication process (as opposed to
-     *     programmatically) then there will be an attached {@link Authentication} object.
-     * </p>
-     *
-     * @param interactionContext
-     */
-    public static Optional<Authentication> authenticationFrom(final @NonNull InteractionContext interactionContext) {
-        return interactionContext.getAttribute(INTERACTION_CONTEXT_KEY, Authentication.class);
-    }
-
-}
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/AuthenticationAbstract.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/AuthenticationAbstract.java
index 449b98e..41e9e79 100644
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/AuthenticationAbstract.java
+++ b/core/security/src/main/java/org/apache/isis/core/security/authentication/AuthenticationAbstract.java
@@ -18,96 +18,8 @@
  */
 package org.apache.isis.core.security.authentication;
 
-import java.io.Serializable;
-import java.util.Objects;
-import java.util.Optional;
+public abstract class AuthenticationAbstract {
 
-import org.apache.isis.applib.services.iactnlayer.InteractionContext;
-import org.apache.isis.applib.util.ToString;
-import org.apache.isis.core.security.authentication.standard.SimpleAuthentication;
 
-import lombok.Getter;
-import lombok.NonNull;
-
-public abstract class AuthenticationAbstract
-implements Authentication {
-
-    private static final long serialVersionUID = 1L;
-
-    protected static final String DEFAULT_AUTH_VALID_CODE = "";
-
-    // -- FIELDS
-
-    @Getter(onMethod_ = {@Override})
-    private final @NonNull InteractionContext interactionContext;
-
-    @Getter(onMethod_ = {@Override})
-    private final @NonNull String validationCode;
-
-    // -- CONSTRUCTOR
-
-    protected AuthenticationAbstract(
-            final @NonNull InteractionContext interactionContext,
-            final @NonNull String validationCode) {
-
-        this.interactionContext = interactionContext;
-        this.interactionContext.putAttribute(INTERACTION_CONTEXT_KEY, this);
-
-        this.validationCode = validationCode;
-    }
-
-
-    // -- WITHERS
-
-    /**
-     * Returns a copy with given {@code interactionContext}.
-     * @param interactionContext
-     */
-    public Authentication withInteractionContext(final @NonNull InteractionContext interactionContext) {
-        return new SimpleAuthentication(interactionContext, validationCode);
-    }
-
-    // -- TO STRING, EQUALS, HASHCODE
-
-    private static final ToString<AuthenticationAbstract> toString = ToString
-            .toString("name", AuthenticationAbstract::getUserName)
-            .thenToString("code", AuthenticationAbstract::getValidationCode);
-
-    @Override
-    public String toString() {
-        return toString.toString(this);
-    }
-
-    @Override
-    public boolean equals(final Object obj) {
-        if (obj == this) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (obj.getClass() != getClass()) {
-            return false;
-        }
-        return isEqualsTo((AuthenticationAbstract) obj);
-    }
-
-    private boolean isEqualsTo(final AuthenticationAbstract other) {
-        if(!Objects.equals(this.getType(), other.getType())) {
-            return false;
-        }
-        if(!Objects.equals(this.getValidationCode(), other.getValidationCode())) {
-            return false;
-        }
-        if(!Objects.equals(this.getInteractionContext(), other.getInteractionContext())) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        return getUserName().hashCode(); // propably good enough to hash on just the user's name
-    }
 
 }
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/AuthenticationProvider.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/AuthenticationProvider.java
index 7c838c7..e675a2c 100644
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/AuthenticationProvider.java
+++ b/core/security/src/main/java/org/apache/isis/core/security/authentication/AuthenticationProvider.java
@@ -21,13 +21,16 @@ package org.apache.isis.core.security.authentication;
 
 import java.util.Optional;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.commons.internal.debug._Probe;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 
 /**
  * Provides the current thread's {@link Authentication}.
  * @since 2.0
+ * @deprecated
  */
+@Deprecated
 public interface AuthenticationProvider {
 
     /**
@@ -37,9 +40,9 @@ public interface AuthenticationProvider {
      * the current thread's {@link org.apache.isis.core.interaction.session.InteractionSession}'s
      * authentication layer stack.
      */
-    Optional<Authentication> currentAuthentication();
+    Optional<InteractionContext> currentAuthentication();
 
-    default Authentication currentAuthenticationElseFail() {
+    default InteractionContext currentAuthenticationElseFail() {
         return currentAuthentication()
                 .orElseThrow(()->
                     _Exceptions.illegalState(
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/AuthenticationRequest.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/AuthenticationRequest.java
index bddafc7..52289a8 100644
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/AuthenticationRequest.java
+++ b/core/security/src/main/java/org/apache/isis/core/security/authentication/AuthenticationRequest.java
@@ -23,6 +23,9 @@ import java.util.stream.Stream;
 
 import javax.annotation.Nullable;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
+import org.apache.isis.applib.services.user.UserMemento;
+
 /**
  * Represents a request to authenticate the user identified by
  * {@link AuthenticationRequest#getName()}.
@@ -30,9 +33,8 @@ import javax.annotation.Nullable;
  * <p>
  *     If successful, then the authentication mechanism is expected to add the
  *     {@link AuthenticationRequest#streamRoles() roles} to the resultant
- *     {@link Authentication} (obtained from the
- *     {@link org.apache.isis.applib.services.user.UserMemento} returned by
- *     {@link Authentication#getUser()}).
+ *     {@link UserMemento} (obtained from
+ *     {@link InteractionContext#getUser()}).
  * </p>
  *
  * @apiNote This is a framework internal class and so does not constitute a formal API.
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/Authenticator.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/Authenticator.java
index 34728d5..0c1db28 100644
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/Authenticator.java
+++ b/core/security/src/main/java/org/apache/isis/core/security/authentication/Authenticator.java
@@ -19,9 +19,11 @@
 
 package org.apache.isis.core.security.authentication;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
+
 /**
  * Represents an authentication mechanism capable of authenticating certain
- * types of {@link AuthenticationRequest} and returning an {@link Authentication}
+ * types of {@link AuthenticationRequest} and returning an {@link InteractionContext}
  * if the credentials are valid.
  *
  * <p>
@@ -44,16 +46,16 @@ public interface Authenticator {
 
     /**
      * Authenticates the provided {@link AuthenticationRequest request},
-     * returning a non-null {@link Authentication} if valid.
+     * returning a non-null {@link InteractionContext} if valid.
      *
      * @param code
      *            - a hint; is guaranteed by the framework to be unique, but the authenticator decides whether to use it or not.
      */
-    Authentication authenticate(AuthenticationRequest request, String code);
+    InteractionContext authenticate(AuthenticationRequest request, String code);
 
     /**
-     * Invalidates this {@link Authentication}, meaning that the user will need
+     * Invalidates this {@link InteractionContext}, meaning that the user will need
      * to log in again to use the application.
      */
-    void logout(Authentication authentication);
+    void logout(InteractionContext context);
 }
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/InteractionContextFactory.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/InteractionContextFactory.java
new file mode 100644
index 0000000..b5fe369
--- /dev/null
+++ b/core/security/src/main/java/org/apache/isis/core/security/authentication/InteractionContextFactory.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.security.authentication;
+
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
+import org.apache.isis.applib.services.user.UserMemento;
+
+import lombok.NonNull;
+
+public final class InteractionContextFactory {
+
+    public static final String DEFAULT_AUTH_VALID_CODE = "";
+
+    public static InteractionContext anonymous() {
+        return InteractionContext
+                .ofUserWithSystemDefaults(
+                        UserMemento
+                            .system()
+                            .withAuthenticationCode(DEFAULT_AUTH_VALID_CODE));
+    }
+
+    public static InteractionContext health() {
+        return InteractionContext
+                .ofUserWithSystemDefaults(
+                        UserMemento
+                            .ofNameAndRoleNames(
+                                "__health", // user name
+                                "__health-role") // role(s)
+                            .withAuthenticationCode(DEFAULT_AUTH_VALID_CODE));
+    }
+
+    public static InteractionContext testing() {
+        return InteractionContext
+                .ofUserWithSystemDefaults(
+                        UserMemento
+                            .ofName("prototyping")
+                            .withAuthenticationCode(DEFAULT_AUTH_VALID_CODE));
+    }
+
+    public static InteractionContext testing(final @NonNull String authenticationCode) {
+        return InteractionContext
+                .ofUserWithSystemDefaults(
+                        UserMemento
+                            .ofName("prototyping")
+                            .withAuthenticationCode(authenticationCode));
+    }
+
+    @Deprecated //TODO remove second arg or probably use InteractionContext.of... instead
+    public static InteractionContext valid(
+            final @NonNull UserMemento user,
+            final @NonNull String authenticationCode) {
+
+        return InteractionContext
+                .ofUserWithSystemDefaults(
+                        user.withAuthenticationCode(authenticationCode));
+    }
+
+}
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/health/HealthAuthentication.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/health/HealthAuthentication.java
deleted file mode 100644
index 9eec19b..0000000
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/health/HealthAuthentication.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you 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
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.core.security.authentication.health;
-
-import org.apache.isis.applib.services.iactnlayer.InteractionContext;
-import org.apache.isis.applib.services.user.UserMemento;
-import org.apache.isis.core.security.authentication.AuthenticationAbstract;
-
-public class HealthAuthentication extends AuthenticationAbstract {
-
-    private static final long serialVersionUID = 1L;
-
-    private static final InteractionContext HEALTH_EXEC_CTX =
-            InteractionContext.ofUserWithSystemDefaults(
-                    UserMemento.ofNameAndRoleNames(
-                            "__health", // user name
-                            "__health-role") // role(s)
-                    );
-
-    public HealthAuthentication() {
-        super(HEALTH_EXEC_CTX, AuthenticationAbstract.DEFAULT_AUTH_VALID_CODE);
-    }
-
-
-}
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/logout/LogoutMenu.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/logout/LogoutMenu.java
index 2e33209..128d2f0 100644
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/logout/LogoutMenu.java
+++ b/core/security/src/main/java/org/apache/isis/core/security/authentication/logout/LogoutMenu.java
@@ -32,11 +32,11 @@ import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.DomainServiceLayout;
 import org.apache.isis.applib.annotation.Nature;
 import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.value.LocalResourcePath;
 import org.apache.isis.applib.value.OpenUrlStrategy;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.core.security.IsisModuleCoreSecurity;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.AuthenticationProvider;
 
 import lombok.RequiredArgsConstructor;
@@ -74,10 +74,11 @@ public class LogoutMenu {
 
     private Object getRedirect() {
         val redirect =  authenticationProvider.currentAuthentication()
-        .map(authentication->
-            authentication.getType() == Authentication.Type.EXTERNAL
-            ? "logout"
-            : "login"
+        .map(InteractionContext::getUser)
+        .map(userMemento->
+            userMemento.getAuthenticationSource().isExternal()
+                ? "logout"
+                : "login"
         )
         .orElse("login");
         switch(redirect) {
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/AuthenticationManager.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/AuthenticationManager.java
index 27bca27..0b809e8 100644
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/AuthenticationManager.java
+++ b/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/AuthenticationManager.java
@@ -35,11 +35,11 @@ import org.springframework.transaction.annotation.Transactional;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.exceptions.unrecoverable.NoAuthenticatorException;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.util.ToString;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Timing;
 import org.apache.isis.commons.internal.collections._Maps;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.AuthenticationRequest;
 import org.apache.isis.core.security.authentication.Authenticator;
 import org.apache.isis.core.security.authentication.standard.RandomCodeGenerator;
@@ -84,7 +84,7 @@ public class AuthenticationManager {
 
     @Transactional(readOnly = true) // let Spring handle the transactional context for this method
     // cannot use final here, as Spring provides a transaction aware proxy for this type
-    public /*final*/ Authentication authenticate(AuthenticationRequest request) {
+    public /*final*/ InteractionContext authenticate(AuthenticationRequest request) {
 
         if (request == null) {
             return null;
@@ -105,7 +105,10 @@ public class AuthenticationManager {
             for (val authenticator : compatibleAuthenticators) {
                 val authentication = authenticator.authenticate(request, getUnusedRandomCode());
                 if (authentication != null) {
-                    userByValidationCode.put(authentication.getValidationCode(), authentication.getUserName());
+                    val userMemento = authentication.getUser();
+                    userByValidationCode.put(
+                            userMemento.getAuthenticationCode(),
+                            userMemento.getName());
                     return authentication;
                 }
             }
@@ -137,23 +140,24 @@ public class AuthenticationManager {
 
 
     // cannot use final here, as Spring provides a transaction aware proxy for this type
-    public /*final*/ boolean isSessionValid(final @Nullable Authentication authentication) {
+    public /*final*/ boolean isSessionValid(final @Nullable InteractionContext authentication) {
         if(authentication==null) {
             return false;
         }
-        if(authentication.getType() == Authentication.Type.EXTERNAL) {
+        val userMemento = authentication.getUser();
+        if(userMemento.getAuthenticationSource().isExternal()) {
             return true;
         }
-        final String userName = userByValidationCode.get(authentication.getValidationCode());
+        final String userName = userByValidationCode.get(userMemento.getAuthenticationCode());
         return authentication.getUser().isCurrentUser(userName);
     }
 
 
-    public void closeSession(Authentication authentication) {
+    public void closeSession(InteractionContext context) {
         for (val authenticator : authenticators) {
-            authenticator.logout(authentication);
+            authenticator.logout(context);
         }
-        userByValidationCode.remove(authentication.getValidationCode());
+        userByValidationCode.remove(context.getUser().getAuthenticationCode());
     }
 
     // -- AUTHENTICATORS
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/singleuser/SingleUserAuthentication.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/singleuser/SingleUserAuthentication.java
deleted file mode 100644
index 4e0d098..0000000
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/singleuser/SingleUserAuthentication.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you 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
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.core.security.authentication.singleuser;
-
-import org.apache.isis.applib.services.iactnlayer.InteractionContext;
-import org.apache.isis.applib.services.user.UserMemento;
-import org.apache.isis.core.security.authentication.AuthenticationAbstract;
-
-public final class SingleUserAuthentication extends AuthenticationAbstract {
-
-    private static final long serialVersionUID = 1L;
-
-    private static final InteractionContext DEFAULT_SINGLE_USER_ENVIRONMENT =
-            InteractionContext.ofUserWithSystemDefaults(
-                    UserMemento.ofName("prototyping"));
-
-    /**
-     * Defaults session's authentication validation code to {@code ""}
-     */
-    public SingleUserAuthentication() {
-        this(AuthenticationAbstract.DEFAULT_AUTH_VALID_CODE);
-    }
-
-    public SingleUserAuthentication(final String authValidationCode) {
-        super(DEFAULT_SINGLE_USER_ENVIRONMENT, authValidationCode);
-    }
-
-}
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/standard/AuthenticatorAbstract.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/standard/AuthenticatorAbstract.java
index 8f44235..41d42c7 100644
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/standard/AuthenticatorAbstract.java
+++ b/core/security/src/main/java/org/apache/isis/core/security/authentication/standard/AuthenticatorAbstract.java
@@ -19,9 +19,9 @@
 
 package org.apache.isis.core.security.authentication.standard;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.user.UserMemento;
 import org.apache.isis.core.security.authentication.AuthenticationRequest;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.Authenticator;
 
 import lombok.val;
@@ -29,11 +29,11 @@ import lombok.val;
 public abstract class AuthenticatorAbstract implements Authenticator {
 
     /**
-     * Default implementation returns a {@link SimpleAuthentication}; can be overridden
+     * Default implementation returns a validated {@link InteractionContext}; can be overridden
      * if required.
      */
     @Override
-    public final Authentication authenticate(
+    public final InteractionContext authenticate(
             final AuthenticationRequest request,
             final String validationCode) {
 
@@ -41,8 +41,9 @@ public abstract class AuthenticatorAbstract implements Authenticator {
             return null;
         }
 
-        val user = UserMemento.ofNameAndRoleNames(request.getName(), request.streamRoles());
-        return SimpleAuthentication.of(user, validationCode);
+        val user = UserMemento.ofNameAndRoleNames(request.getName(), request.streamRoles())
+                .withAuthenticationCode(validationCode);
+        return InteractionContext.ofUserWithSystemDefaults(user);
     }
 
 
@@ -53,7 +54,7 @@ public abstract class AuthenticatorAbstract implements Authenticator {
     protected abstract boolean isValid(AuthenticationRequest request);
 
     @Override
-    public final void logout(final Authentication session) {
+    public final void logout(final InteractionContext session) {
         // no-op
     }
 
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/standard/SimpleAuthentication.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/standard/SimpleAuthentication.java
deleted file mode 100644
index 887f9ad..0000000
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/standard/SimpleAuthentication.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you 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
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.isis.core.security.authentication.standard;
-
-import org.apache.isis.applib.services.iactnlayer.InteractionContext;
-import org.apache.isis.applib.services.user.UserMemento;
-import org.apache.isis.core.security.authentication.AuthenticationAbstract;
-
-import lombok.Getter;
-import lombok.NonNull;
-import lombok.Setter;
-
-public class SimpleAuthentication
-extends AuthenticationAbstract {
-
-    private static final long serialVersionUID = 1L;
-
-    // -- FACTORIES
-
-    public static SimpleAuthentication of(
-            final @NonNull UserMemento user,
-            final @NonNull String validationCode) {
-        return new SimpleAuthentication(InteractionContext.ofUserWithSystemDefaults(user), validationCode);
-    }
-
-    public static SimpleAuthentication validOf(
-            final @NonNull UserMemento user) {
-        return of(user, DEFAULT_AUTH_VALID_CODE);
-    }
-
-    public static SimpleAuthentication validOf(
-            final @NonNull InteractionContext interactionContext) {
-        return new SimpleAuthentication(interactionContext, DEFAULT_AUTH_VALID_CODE);
-    }
-
-    // -- CONSTRUCTOR
-
-    public SimpleAuthentication(
-            final @NonNull InteractionContext interactionContext,
-            final @NonNull String validationCode) {
-        super(interactionContext, validationCode);
-    }
-
-    @Getter @Setter
-    private Type type = Type.DEFAULT;
-
-}
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authorization/Authorizor.java b/core/security/src/main/java/org/apache/isis/core/security/authorization/Authorizor.java
index 37a7711..30dc9e3 100644
--- a/core/security/src/main/java/org/apache/isis/core/security/authorization/Authorizor.java
+++ b/core/security/src/main/java/org/apache/isis/core/security/authorization/Authorizor.java
@@ -20,11 +20,11 @@
 package org.apache.isis.core.security.authorization;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.core.security.authentication.Authentication;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 
 /**
  * Represents a mechanism to evaluate whether the current user (as represented
- * by {@link Authentication} can either view or invoke the domain object
+ * by {@link InteractionContext} can either view or invoke the domain object
  * feature (as represented by {@link Identifier}.
  *
  * @apiNote This is a framework internal class and so does not constitute a formal API.
@@ -34,13 +34,13 @@ import org.apache.isis.core.security.authentication.Authentication;
 public interface Authorizor {
 
     /**
-     * Whether the current {@link Authentication user} can view the
+     * Whether the current {@link InteractionContext user} can view the
      * domain object feature (represented by {@link Identifier}).
      */
-    boolean isVisible(Authentication authentication, Identifier identifier);
+    boolean isVisible(InteractionContext authentication, Identifier identifier);
 
     /**
-     * Whether the current {@link Authentication user} can invoke the
+     * Whether the current {@link InteractionContext user} can invoke the
      * domain object feature (represented by {@link Identifier}).
      *
      * <p>
@@ -48,6 +48,6 @@ public interface Authorizor {
      *     greyed out/disabled.
      * </p>
      */
-    boolean isUsable(Authentication authentication, Identifier identifier);
+    boolean isUsable(InteractionContext authentication, Identifier identifier);
 
 }
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authorization/manager/AuthorizationManager.java b/core/security/src/main/java/org/apache/isis/core/security/authorization/manager/AuthorizationManager.java
index 24a9dfa..482f0f3 100644
--- a/core/security/src/main/java/org/apache/isis/core/security/authorization/manager/AuthorizationManager.java
+++ b/core/security/src/main/java/org/apache/isis/core/security/authorization/manager/AuthorizationManager.java
@@ -32,8 +32,8 @@ import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.sudo.SudoService;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authorization.Authorizor;
 
 import lombok.val;
@@ -78,7 +78,7 @@ public class AuthorizationManager {
      * </p>
      */
     public boolean isUsable(
-            final Authentication authentication,
+            final InteractionContext authentication,
             final Identifier identifier) {
         if (isPerspectiveMember(identifier)) {
             return true;
@@ -101,7 +101,7 @@ public class AuthorizationManager {
      * </p>
      */
     public boolean isVisible(
-            final Authentication authentication,
+            final InteractionContext authentication,
             final Identifier identifier) {
         if (isPerspectiveMember(identifier)) {
             return true;
@@ -122,7 +122,7 @@ public class AuthorizationManager {
     // -- HELPER
 
     private static boolean containsSudoSuperuserRole(
-            final @Nullable Authentication session) {
+            final @Nullable InteractionContext session) {
         if(session==null || session.getUser()==null) {
             return false;
         }
diff --git a/core/security/src/test/java/org/apache/isis/security/EncodabilityContractTest.java b/core/security/src/test/java/org/apache/isis/security/EncodabilityContractTest.java
index 98bcc9d..2670a9a 100644
--- a/core/security/src/test/java/org/apache/isis/security/EncodabilityContractTest.java
+++ b/core/security/src/test/java/org/apache/isis/security/EncodabilityContractTest.java
@@ -32,17 +32,16 @@ import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.user.UserMemento;
 import org.apache.isis.commons.internal.base._Casts;
-import org.apache.isis.core.security.authentication.Authentication;
-import org.apache.isis.core.security.authentication.standard.SimpleAuthentication;
 
 import lombok.SneakyThrows;
 import lombok.val;
 
 public abstract class EncodabilityContractTest {
 
-    protected Authentication simpleAuthSession;
+    protected InteractionContext authContext;
     protected Serializable serializable;
 
     public EncodabilityContractTest() {
@@ -52,7 +51,9 @@ public abstract class EncodabilityContractTest {
     @Before
     public void setUp() throws Exception {
         serializable = createEncodable();
-        simpleAuthSession = SimpleAuthentication.validOf(UserMemento.ofName("test"));
+        authContext = InteractionContext.ofUserWithSystemDefaults(
+                UserMemento.ofName("test")
+                    .withAuthenticationCode("test_code"));
     }
 
     /**
@@ -70,16 +71,16 @@ public abstract class EncodabilityContractTest {
         val decodedObject = doRoundTrip(serializable);
         assertRoundtripped(decodedObject, serializable);
     }
-    
+
     @SneakyThrows
     private static <T extends Serializable> T doRoundTrip(T serializable) {
-        
+
         val buffer = new ByteArrayOutputStream();
-        
+
         try(val out = new ObjectOutputStream(buffer)) {
             out.writeObject(serializable);
         }
-        
+
         try(val in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray()))) {
             val decodedObject = in.readObject();
             return _Casts.uncheckedCast(decodedObject);
diff --git a/core/security/src/test/java/org/apache/isis/security/authentication/standard/SimpleSessionEncodabilityNoRolesTest.java b/core/security/src/test/java/org/apache/isis/security/authentication/standard/SimpleSessionEncodabilityNoRolesTest.java
index bba6b28..918f7bd 100644
--- a/core/security/src/test/java/org/apache/isis/security/authentication/standard/SimpleSessionEncodabilityNoRolesTest.java
+++ b/core/security/src/test/java/org/apache/isis/security/authentication/standard/SimpleSessionEncodabilityNoRolesTest.java
@@ -21,14 +21,15 @@ package org.apache.isis.security.authentication.standard;
 
 import java.io.Serializable;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.user.UserMemento;
-import org.apache.isis.core.security.authentication.standard.SimpleAuthentication;
 
-public class SimpleSessionEncodabilityNoRolesTest extends SimpleSessionEncodabilityTestAbstract {
+public class SimpleSessionEncodabilityNoRolesTest
+extends SimpleSessionEncodabilityTestAbstract {
 
     @Override
     protected Serializable createEncodable() {
-        return SimpleAuthentication.validOf(UserMemento.ofName("joe"));
+        return InteractionContext.ofUserWithSystemDefaults(UserMemento.ofName("joe"));
     }
 
 }
diff --git a/core/security/src/test/java/org/apache/isis/security/authentication/standard/SimpleSessionEncodabilityTestAbstract.java b/core/security/src/test/java/org/apache/isis/security/authentication/standard/SimpleSessionEncodabilityTestAbstract.java
index a4d25b3..110919e 100644
--- a/core/security/src/test/java/org/apache/isis/security/authentication/standard/SimpleSessionEncodabilityTestAbstract.java
+++ b/core/security/src/test/java/org/apache/isis/security/authentication/standard/SimpleSessionEncodabilityTestAbstract.java
@@ -23,24 +23,25 @@ import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-import org.apache.isis.core.security.authentication.AuthenticationAbstract;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.security.EncodabilityContractTest;
 
-public abstract class SimpleSessionEncodabilityTestAbstract extends EncodabilityContractTest {
+public abstract class SimpleSessionEncodabilityTestAbstract
+extends EncodabilityContractTest {
 
     @Override
     protected void assertRoundtripped(final Object decodedEncodable, final Object originalEncodable) {
-        final AuthenticationAbstract decoded = (AuthenticationAbstract) decodedEncodable;
-        final AuthenticationAbstract original = (AuthenticationAbstract) originalEncodable;
+        final InteractionContext decoded = (InteractionContext) decodedEncodable;
+        final InteractionContext original = (InteractionContext) originalEncodable;
 
         assertThat(decoded.getUser(), is(equalTo(original.getUser()))); // redundant shortcut
 
-        assertThat(decoded.getInteractionContext().getTimeZone(), is(equalTo(original.getInteractionContext().getTimeZone())));
-        assertThat(decoded.getInteractionContext().getLocale(), is(equalTo(original.getInteractionContext().getLocale())));
-        assertThat(decoded.getInteractionContext().getUser(), is(equalTo(original.getInteractionContext().getUser())));
-        assertThat(decoded.getInteractionContext().getClock(), is(equalTo(original.getInteractionContext().getClock())));
+        assertThat(decoded.getTimeZone(), is(equalTo(original.getTimeZone())));
+        assertThat(decoded.getLocale(), is(equalTo(original.getLocale())));
+        assertThat(decoded.getUser(), is(equalTo(original.getUser())));
+        assertThat(decoded.getClock(), is(equalTo(original.getClock())));
 
-        assertThat(decoded.getInteractionContext(), is(equalTo(original.getInteractionContext())));
+        assertThat(decoded, is(equalTo(original)));
     }
 
 }
diff --git a/core/security/src/test/java/org/apache/isis/security/authentication/standard/SimpleSessionEncodabilityWithRolesTest.java b/core/security/src/test/java/org/apache/isis/security/authentication/standard/SimpleSessionEncodabilityWithRolesTest.java
index accf927..92a6979 100644
--- a/core/security/src/test/java/org/apache/isis/security/authentication/standard/SimpleSessionEncodabilityWithRolesTest.java
+++ b/core/security/src/test/java/org/apache/isis/security/authentication/standard/SimpleSessionEncodabilityWithRolesTest.java
@@ -21,14 +21,16 @@ package org.apache.isis.security.authentication.standard;
 
 import java.io.Serializable;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.user.UserMemento;
-import org.apache.isis.core.security.authentication.standard.SimpleAuthentication;
 
-public class SimpleSessionEncodabilityWithRolesTest extends SimpleSessionEncodabilityTestAbstract {
+public class SimpleSessionEncodabilityWithRolesTest
+extends SimpleSessionEncodabilityTestAbstract {
 
     @Override
     protected Serializable createEncodable() {
-        return SimpleAuthentication.validOf(UserMemento.ofNameAndRoleNames("joe", "role1", "role2"));
+        return InteractionContext.ofUserWithSystemDefaults(
+                UserMemento.ofNameAndRoleNames("joe", "role1", "role2"));
     }
 
 }
diff --git a/core/security/src/test/java/org/apache/isis/security/authentication/standard/StandardAuthenticationManager_AuthenticationTest.java b/core/security/src/test/java/org/apache/isis/security/authentication/standard/StandardAuthenticationManager_AuthenticationTest.java
index a5f683f..241a53a 100644
--- a/core/security/src/test/java/org/apache/isis/security/authentication/standard/StandardAuthenticationManager_AuthenticationTest.java
+++ b/core/security/src/test/java/org/apache/isis/security/authentication/standard/StandardAuthenticationManager_AuthenticationTest.java
@@ -24,16 +24,16 @@ import java.util.Collections;
 import org.junit.Before;
 import org.junit.Test;
 
-import org.apache.isis.core.security.authentication.Authentication;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.core.security.authentication.AuthenticationRequestPassword;
 import org.apache.isis.core.security.authentication.manager.AnonymousInteractionFactory;
 import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
 import org.apache.isis.core.security.authentication.standard.RandomCodeGeneratorDefault;
 import org.apache.isis.security.AuthenticatorsForTesting;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-
 public class StandardAuthenticationManager_AuthenticationTest {
 
     private AuthenticationManager authenticationManager;
@@ -50,7 +50,7 @@ public class StandardAuthenticationManager_AuthenticationTest {
     @Test
     public void newlyCreatedAuthenticationShouldBeValid() throws Exception {
         final AuthenticationRequestPassword request = new AuthenticationRequestPassword("foo", "bar");
-        final Authentication authentication = authenticationManager.authenticate(request);
+        final InteractionContext authentication = authenticationManager.authenticate(request);
 
         assertThat(authenticationManager.isSessionValid(authentication), is(true));
     }
@@ -58,7 +58,7 @@ public class StandardAuthenticationManager_AuthenticationTest {
     @Test
     public void newlyCreatedAuthentication_whenUnauthorizedUser_shouldBeRejected() throws Exception {
         final AuthenticationRequestPassword request = new AuthenticationRequestPassword("me", "pass");
-        final Authentication authentication = authenticationManager.authenticate(request);
+        final InteractionContext authentication = authenticationManager.authenticate(request);
 
         assertThat(authenticationManager.isSessionValid(authentication), is(false));
     }
diff --git a/core/webapp/src/main/java/org/apache/isis/core/webapp/health/HealthIndicatorUsingHealthCheckService.java b/core/webapp/src/main/java/org/apache/isis/core/webapp/health/HealthIndicatorUsingHealthCheckService.java
index 853b6e2..6f561ec 100644
--- a/core/webapp/src/main/java/org/apache/isis/core/webapp/health/HealthIndicatorUsingHealthCheckService.java
+++ b/core/webapp/src/main/java/org/apache/isis/core/webapp/health/HealthIndicatorUsingHealthCheckService.java
@@ -29,7 +29,7 @@ import org.springframework.stereotype.Component;
 
 import org.apache.isis.applib.services.health.HealthCheckService;
 import org.apache.isis.core.interaction.session.InteractionFactory;
-import org.apache.isis.core.security.authentication.health.HealthAuthentication;
+import org.apache.isis.core.security.authentication.InteractionContextFactory;
 
 import lombok.val;
 
@@ -50,9 +50,11 @@ public class HealthIndicatorUsingHealthCheckService extends AbstractHealthIndica
 
     @Override
     protected void doHealthCheck(Health.Builder builder) throws Exception {
-        val health = healthCheckServiceIfAny.map(healthCheckService ->
-                        isisInteractionFactory.callAuthenticated(new HealthAuthentication(), healthCheckService::check))
-                     .orElse(null);
+        val health = healthCheckServiceIfAny
+                .map(healthCheckService ->
+                    isisInteractionFactory
+                        .call(InteractionContextFactory.health(), healthCheckService::check))
+                .orElse(null);
         if(health != null) {
             final boolean result = health.getResult();
             if(result) {
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/job/ReplicateAndReplayJob.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/job/ReplicateAndReplayJob.java
index 5c78680..0716308 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/job/ReplicateAndReplayJob.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/job/ReplicateAndReplayJob.java
@@ -25,10 +25,9 @@ import org.quartz.Job;
 import org.quartz.JobExecutionContext;
 import org.quartz.PersistJobDataAfterExecution;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.user.UserMemento;
 import org.apache.isis.core.interaction.session.InteractionFactory;
-import org.apache.isis.core.security.authentication.Authentication;
-import org.apache.isis.core.security.authentication.standard.SimpleAuthentication;
 import org.apache.isis.extensions.commandreplay.secondary.SecondaryStatus;
 import org.apache.isis.extensions.commandreplay.secondary.config.SecondaryConfig;
 import org.apache.isis.extensions.commandreplay.secondary.jobcallables.IsTickingClockInitialized;
@@ -47,7 +46,7 @@ public class ReplicateAndReplayJob implements Job {
 
     @Inject SecondaryConfig secondaryConfig;
 
-    Authentication authentication;
+    InteractionContext authentication;
 
     @Override
     public void execute(final JobExecutionContext quartzContext) {
@@ -60,7 +59,7 @@ public class ReplicateAndReplayJob implements Job {
                     secondaryConfig.getPrimaryUser(),
                     secondaryConfig.getQuartzRoles().stream());
 
-            authentication = SimpleAuthentication.validOf(user);
+            authentication = InteractionContext.ofUserWithSystemDefaults(user);
             exec(quartzContext);
         }
     }
@@ -88,7 +87,7 @@ public class ReplicateAndReplayJob implements Job {
 
             case OK:
                 val newStatus =
-                        isisInteractionFactory.callAuthenticated(authentication, new ReplicateAndRunCommands());
+                        isisInteractionFactory.call(authentication, new ReplicateAndRunCommands());
 
                 if(newStatus != null) {
                     ssh.setSecondaryStatus(newStatus);
@@ -105,8 +104,8 @@ public class ReplicateAndReplayJob implements Job {
         }
     }
 
-    private boolean isTickingClockInitialized(final Authentication authentication) {
-        return isisInteractionFactory.callAuthenticated(authentication, new IsTickingClockInitialized());
+    private boolean isTickingClockInitialized(final InteractionContext authentication) {
+        return isisInteractionFactory.call(authentication, new IsTickingClockInitialized());
     }
 
 }
diff --git a/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/user/dom/ApplicationUser.java b/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/user/dom/ApplicationUser.java
index 1e460ab..ab53576 100644
--- a/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/user/dom/ApplicationUser.java
+++ b/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/user/dom/ApplicationUser.java
@@ -22,7 +22,6 @@ import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 
@@ -554,11 +553,10 @@ public abstract class ApplicationUser
         }
 
         // is runAsAdministrator?
-        final List<RoleMemento> roles = currentUser.getRoles();
 
         val adminRoleSuffix = ":" + getAdminRoleName();
 
-        for (final RoleMemento role : roles) {
+        for (final RoleMemento role : currentUser.getRoles()) {
             final String roleName = role.getName();
             // format is realmName:roleName.
             // since we don't know what the realm's name is (depends on its configuration in shiro.ini),
@@ -598,7 +596,7 @@ public abstract class ApplicationUser
 
     @Override
     public int compareTo(final org.apache.isis.extensions.secman.applib.user.dom.ApplicationUser other) {
-        return contract.compare(this, (ApplicationUser) other);
+        return contract.compare(this, other);
     }
 
     @Override
diff --git a/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/authenticator/AuthenticatorSecman.java b/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/authenticator/AuthenticatorSecman.java
index 5bbd2d9..f30f014 100644
--- a/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/authenticator/AuthenticatorSecman.java
+++ b/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/authenticator/AuthenticatorSecman.java
@@ -22,12 +22,12 @@ import java.util.stream.Stream;
 
 import javax.inject.Inject;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.user.UserMemento;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.AuthenticationRequest;
 import org.apache.isis.core.security.authentication.AuthenticationRequestPassword;
 import org.apache.isis.core.security.authentication.Authenticator;
-import org.apache.isis.core.security.authentication.standard.SimpleAuthentication;
+import org.apache.isis.core.security.authentication.InteractionContextFactory;
 import org.apache.isis.extensions.secman.applib.role.dom.ApplicationRole;
 import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUser;
 import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUserRepository;
@@ -63,7 +63,7 @@ public class AuthenticatorSecman implements Authenticator {
     }
 
     @Override
-    public Authentication authenticate(final AuthenticationRequest request, final String code) {
+    public InteractionContext authenticate(final AuthenticationRequest request, final String code) {
         val authRequest = (AuthenticationRequestPassword) request;
         val username = authRequest.getName();
         val password = authRequest.getPassword();
@@ -80,13 +80,13 @@ public class AuthenticatorSecman implements Authenticator {
                             appUser.getRoles().stream().map(ApplicationRole::getName),
                             request.streamRoles());
                     val user = UserMemento.ofNameAndRoleNames(username, roleNames);
-                    return SimpleAuthentication.of(user, code);
+                    return InteractionContextFactory.valid(user, code);
                 })
                 .orElse(null);
     }
 
     @Override
-    public void logout(final Authentication session) {
+    public void logout(final InteractionContext context) {
         // nothing needs to be done.  On logout the top-level AuthenticationManager
         // will invalidate the validation code held in the Authentication
         // object; this will cause the next http request made by the user to
diff --git a/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/authorizor/AuthorizorSecman.java b/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/authorizor/AuthorizorSecman.java
index 4e1c9d3..421d76d 100644
--- a/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/authorizor/AuthorizorSecman.java
+++ b/extensions/security/secman/integration/src/main/java/org/apache/isis/extensions/secman/integration/authorizor/AuthorizorSecman.java
@@ -28,14 +28,12 @@ import org.springframework.stereotype.Service;
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.services.appfeat.ApplicationFeatureId;
-import org.apache.isis.core.security.authentication.Authentication;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.core.security.authorization.Authorizor;
 import org.apache.isis.extensions.secman.applib.permission.dom.ApplicationPermissionMode;
 import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUser;
 import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUserRepository;
 
-import lombok.extern.log4j.Log4j2;
-
 /**
  * @since 2.0 {@index}
  */
@@ -48,24 +46,24 @@ public class AuthorizorSecman implements Authorizor {
     @Inject ApplicationUserRepository applicationUserRepository;
 
     @Override
-    public boolean isVisible(final Authentication authentication, final Identifier identifier) {
+    public boolean isVisible(final InteractionContext authentication, final Identifier identifier) {
         return grants(authentication, identifier, ApplicationPermissionMode.VIEWING);
     }
 
     @Override
-    public boolean isUsable(final Authentication authentication, final Identifier identifier) {
+    public boolean isUsable(final InteractionContext authentication, final Identifier identifier) {
         return grants(authentication, identifier, ApplicationPermissionMode.CHANGING);
     }
 
     // -- HELPER
 
     private boolean grants(
-            final Authentication authentication,
+            final InteractionContext authentication,
             final Identifier identifier,
             final ApplicationPermissionMode permissionMode) {
 
         return applicationUserRepository
-        .findByUsername(authentication.getUserName())
+        .findByUsername(authentication.getUser().getName())
         .map(ApplicationUser::getPermissionSet)
         .map(permissionSet->permissionSet.grants(
                 ApplicationFeatureId.fromIdentifier(identifier),
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/AuthSessionStoreUtil.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/AuthSessionStoreUtil.java
index 62c6026..7ec64db 100644
--- a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/AuthSessionStoreUtil.java
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/AuthSessionStoreUtil.java
@@ -25,7 +25,7 @@ import javax.servlet.http.HttpSession;
 
 import com.vaadin.flow.server.VaadinSession;
 
-import org.apache.isis.core.security.authentication.Authentication;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 
 import lombok.NonNull;
 import lombok.experimental.UtilityClass;
@@ -42,32 +42,32 @@ public class AuthSessionStoreUtil {
 
     public static void put(
             @NonNull final HttpSession httpSession,
-            @Nullable final Authentication auth) {
-        httpSession.setAttribute(Authentication.class.getName(), auth);
+            @Nullable final InteractionContext auth) {
+        httpSession.setAttribute(InteractionContext.class.getName(), auth);
     }
 
-    public static Optional<Authentication> get(
+    public static Optional<InteractionContext> get(
             @NonNull final HttpSession httpSession) {
         return Optional.ofNullable(
-                (Authentication)httpSession
-                .getAttribute(Authentication.class.getName()));
+                (InteractionContext)httpSession
+                .getAttribute(InteractionContext.class.getName()));
     }
 
     /** when within a VaadinSession */
     public static void put(
-            @Nullable final Authentication auth) {
+            @Nullable final InteractionContext auth) {
         Optional.ofNullable(VaadinSession.getCurrent())
         .map(VaadinSession::getSession)
         .ifPresent(sessionVaa->{
-            sessionVaa.setAttribute(Authentication.class.getName(), auth);
+            sessionVaa.setAttribute(InteractionContext.class.getName(), auth);
         });
     }
 
     /** when within a VaadinSession */
-    public static Optional<Authentication> get() {
+    public static Optional<InteractionContext> get() {
         return Optional.ofNullable(
-                (Authentication)VaadinSession.getCurrent().getSession()
-                .getAttribute(Authentication.class.getName()));
+                (InteractionContext)VaadinSession.getCurrent().getSession()
+                .getAttribute(InteractionContext.class.getName()));
     }
 
     /** when within a VaadinSession */
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/LogoutHandlerVaa.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/LogoutHandlerVaa.java
index c947cac..ada7cce 100644
--- a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/LogoutHandlerVaa.java
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/LogoutHandlerVaa.java
@@ -47,7 +47,7 @@ public class LogoutHandlerVaa implements LogoutHandler {
 
         AuthSessionStoreUtil.get()
         .ifPresent(auth->{
-            log.info("logging out {}", auth.getUserName());
+            log.info("logging out {}", auth.getUser().getName());
             // logout AuthenticationManager
             metaModelContext.getAuthenticationManager().closeSession(auth);
             AuthSessionStoreUtil.clear();
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/VaadinAuthenticationHandler.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/VaadinAuthenticationHandler.java
index 75adb6a..30f1025 100644
--- a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/VaadinAuthenticationHandler.java
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/VaadinAuthenticationHandler.java
@@ -82,7 +82,7 @@ implements
                 .authenticate(authenticationRequest);
 
         if(authentication!=null) {
-            log.debug("logging in {}", authentication.getUserName());
+            log.debug("logging in {}", authentication.getUser().getName());
             AuthSessionStoreUtil.put(authentication);
             return true;
         }
@@ -99,7 +99,7 @@ implements
      */
     public <R> R callAuthenticated(Callable<R> callable) {
         return AuthSessionStoreUtil.get()
-                .map(authentication->isisInteractionFactory.callAuthenticated(authentication, callable))
+                .map(authentication->isisInteractionFactory.call(authentication, callable))
                 .orElse(null); // TODO redirect to login
     }
 
@@ -121,7 +121,7 @@ implements
 
         val authentication = AuthSessionStoreUtil.get().orElse(null);
         if(authentication!=null) {
-            isisInteractionFactory.openInteraction(authentication.getInteractionContext());
+            isisInteractionFactory.openInteraction(authentication);
             return; // access granted
         }
         // otherwise redirect to login page
diff --git a/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisServletForVaadin.java b/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisServletForVaadin.java
index 06422fe..0ffa451 100644
--- a/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisServletForVaadin.java
+++ b/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisServletForVaadin.java
@@ -29,7 +29,6 @@ import com.vaadin.flow.spring.SpringServlet;
 import org.springframework.context.ApplicationContext;
 
 import org.apache.isis.applib.services.iactn.Interaction;
-import org.apache.isis.applib.services.iactnlayer.InteractionService;
 import org.apache.isis.core.interaction.session.InteractionFactory;
 import org.apache.isis.incubator.viewer.vaadin.ui.auth.AuthSessionStoreUtil;
 
@@ -69,7 +68,7 @@ extends SpringServlet {
         log.debug("new request incoming (authentication={})", authentication);
 
         if(authentication!=null) {
-            interactionFactory.runAuthenticated(authentication, ()->{
+            interactionFactory.run(authentication, ()->{
                 super.service(request, response);
             });
         } else {
diff --git a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/testing/AbstractFacetFactoryTest.java b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/testing/AbstractFacetFactoryTest.java
index 10f95d0..acbb3fa 100644
--- a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/testing/AbstractFacetFactoryTest.java
+++ b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/testing/AbstractFacetFactoryTest.java
@@ -28,6 +28,7 @@ import org.junit.Rule;
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.i18n.TranslationService;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.repository.EntityState;
 import org.apache.isis.commons.collections.ImmutableEnumSet;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
@@ -42,8 +43,8 @@ import org.apache.isis.core.metamodel.facets.FacetedMethod;
 import org.apache.isis.core.metamodel.facets.FacetedMethodParameter;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.AuthenticationProvider;
+import org.apache.isis.core.security.authentication.InteractionContextFactory;
 import org.apache.isis.persistence.jdo.provider.entities.JdoFacetContext;
 
 import junit.framework.TestCase;
@@ -68,7 +69,7 @@ public abstract class AbstractFacetFactoryTest extends TestCase {
 
     protected TranslationService mockTranslationService;
     protected AuthenticationProvider mockAuthenticationProvider;
-    protected Authentication mockAuthentication;
+    protected final InteractionContext iaContext = InteractionContextFactory.testing();
     protected SpecificationLoader mockSpecificationLoader;
     protected MethodRemoverForTesting methodRemover;
 
@@ -108,10 +109,7 @@ public abstract class AbstractFacetFactoryTest extends TestCase {
         methodRemover = new MethodRemoverForTesting();
 
         mockAuthenticationProvider = context.mock(AuthenticationProvider.class);
-
         mockTranslationService = context.mock(TranslationService.class);
-        mockAuthentication = context.mock(Authentication.class);
-
         mockSpecificationLoader = context.mock(SpecificationLoader.class);
 
         metaModelContext = MetaModelContext_forTesting.builder()
@@ -123,7 +121,7 @@ public abstract class AbstractFacetFactoryTest extends TestCase {
         context.checking(new Expectations() {{
 
             allowing(mockAuthenticationProvider).currentAuthentication();
-            will(returnValue(Optional.of(mockAuthentication)));
+            will(returnValue(Optional.of(iaContext)));
         }});
 
         ((MetaModelContextAware)facetHolder).setMetaModelContext(metaModelContext);
diff --git a/security/bypass/src/main/java/org/apache/isis/security/bypass/authorization/AuthorizorBypass.java b/security/bypass/src/main/java/org/apache/isis/security/bypass/authorization/AuthorizorBypass.java
index 728edf1..9bb990f 100644
--- a/security/bypass/src/main/java/org/apache/isis/security/bypass/authorization/AuthorizorBypass.java
+++ b/security/bypass/src/main/java/org/apache/isis/security/bypass/authorization/AuthorizorBypass.java
@@ -27,7 +27,7 @@ import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.OrderPrecedence;
-import org.apache.isis.core.security.authentication.Authentication;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.core.security.authorization.Authorizor;
 
 /**
@@ -40,12 +40,12 @@ import org.apache.isis.core.security.authorization.Authorizor;
 public class AuthorizorBypass implements Authorizor {
 
     @Override
-    public boolean isVisible(final Authentication authentication, final Identifier identifier) {
+    public boolean isVisible(final InteractionContext authentication, final Identifier identifier) {
         return true;
     }
 
     @Override
-    public boolean isUsable(final Authentication authentication, final Identifier identifier) {
+    public boolean isUsable(final InteractionContext authentication, final Identifier identifier) {
         return true;
     }
 
diff --git a/security/keycloak/src/main/java/org/apache/isis/security/keycloak/authentication/AuthenticatorKeycloak.java b/security/keycloak/src/main/java/org/apache/isis/security/keycloak/authentication/AuthenticatorKeycloak.java
index 5da1e3d..9a861ed 100644
--- a/security/keycloak/src/main/java/org/apache/isis/security/keycloak/authentication/AuthenticatorKeycloak.java
+++ b/security/keycloak/src/main/java/org/apache/isis/security/keycloak/authentication/AuthenticatorKeycloak.java
@@ -27,9 +27,9 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
-import org.apache.isis.core.security.authentication.AuthenticationRequest;
-import org.apache.isis.core.security.authentication.Authentication;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.core.security.authentication.AuthenticationProvider;
+import org.apache.isis.core.security.authentication.AuthenticationRequest;
 import org.apache.isis.core.security.authentication.Authenticator;
 
 /**
@@ -50,13 +50,13 @@ public class AuthenticatorKeycloak implements Authenticator {
     }
 
     @Override
-    public Authentication authenticate(final AuthenticationRequest request, final String code) {
+    public InteractionContext authenticate(final AuthenticationRequest request, final String code) {
         // HTTP request filters should already have taken care of Authentication creation
         return authenticationProvider.currentAuthentication().orElse(null);
     }
 
     @Override
-    public void logout(final Authentication session) {
+    public void logout(final InteractionContext session) {
     }
 
 }
diff --git a/security/keycloak/src/main/java/org/apache/isis/security/keycloak/webmodule/KeycloakFilter.java b/security/keycloak/src/main/java/org/apache/isis/security/keycloak/webmodule/KeycloakFilter.java
index 3f0831a..6f423ea 100644
--- a/security/keycloak/src/main/java/org/apache/isis/security/keycloak/webmodule/KeycloakFilter.java
+++ b/security/keycloak/src/main/java/org/apache/isis/security/keycloak/webmodule/KeycloakFilter.java
@@ -34,11 +34,10 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.springframework.beans.factory.annotation.Autowired;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.user.UserMemento;
-import org.apache.isis.applib.services.iactnlayer.InteractionService;
+import org.apache.isis.applib.services.user.UserMemento.AuthenticationSource;
 import org.apache.isis.core.interaction.session.InteractionFactory;
-import org.apache.isis.core.security.authentication.Authentication;
-import org.apache.isis.core.security.authentication.standard.SimpleAuthentication;
 
 import lombok.val;
 
@@ -66,15 +65,13 @@ public class KeycloakFilter implements Filter {
         }
         final List<String> roles = toClaims(rolesHeader);
 
-        val user = UserMemento.ofNameAndRoleNames(userid, roles.stream());
-        val authentication = SimpleAuthentication.of(user, subjectHeader);
-        authentication.setType(Authentication.Type.EXTERNAL);
+        val user = UserMemento.ofNameAndRoleNames(userid, roles.stream())
+                .withAuthenticationSource(AuthenticationSource.EXTERNAL)
+                .withAuthenticationCode(subjectHeader);
 
-        interactionFactory.runAuthenticated(
-                authentication,
-                ()->{
-                        filterChain.doFilter(servletRequest, servletResponse);
-                });
+        interactionFactory.run(
+                InteractionContext.ofUserWithSystemDefaults(user),
+                ()->filterChain.doFilter(servletRequest, servletResponse));
     }
 
     static List<String> toClaims(final String claimsHeader) {
diff --git a/security/shiro/src/main/java/org/apache/isis/security/shiro/authentication/AuthenticatorShiro.java b/security/shiro/src/main/java/org/apache/isis/security/shiro/authentication/AuthenticatorShiro.java
index 8e1f471..6100f1e 100644
--- a/security/shiro/src/main/java/org/apache/isis/security/shiro/authentication/AuthenticatorShiro.java
+++ b/security/shiro/src/main/java/org/apache/isis/security/shiro/authentication/AuthenticatorShiro.java
@@ -47,14 +47,14 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.user.UserMemento;
 import org.apache.isis.commons.internal.collections._Sets;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.security.authentication.AuthenticationRequest;
 import org.apache.isis.core.security.authentication.AuthenticationRequestPassword;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.Authenticator;
-import org.apache.isis.core.security.authentication.standard.SimpleAuthentication;
+import org.apache.isis.core.security.authentication.InteractionContextFactory;
 import org.apache.isis.core.security.authorization.Authorizor;
 import org.apache.isis.security.shiro.context.ShiroSecurityContext;
 
@@ -100,7 +100,7 @@ public class AuthenticatorShiro implements Authenticator {
     }
 
     @Override
-    public Authentication authenticate(final AuthenticationRequest request, final String code) {
+    public InteractionContext authenticate(final AuthenticationRequest request, final String code) {
         RealmSecurityManager securityManager = getSecurityManager();
         if(securityManager == null) {
             return null;
@@ -152,14 +152,14 @@ public class AuthenticatorShiro implements Authenticator {
     }
 
     @Override
-    public void logout(final Authentication session) {
+    public void logout(final InteractionContext context) {
         Subject currentSubject = SecurityUtils.getSubject();
         if(currentSubject.isAuthenticated()) {
             currentSubject.logout();
         }
     }
 
-    Authentication authenticationFor(
+    InteractionContext authenticationFor(
             AuthenticationRequest request,
             String validationCode,
             AuthenticationToken token,
@@ -173,7 +173,7 @@ public class AuthenticatorShiro implements Authenticator {
                 request.streamRoles());
 
         val user = UserMemento.ofNameAndRoleNames(request.getName(), roles);
-        return SimpleAuthentication.of(user, validationCode);
+        return InteractionContextFactory.valid(user, validationCode);
     }
 
     /**
diff --git a/security/shiro/src/main/java/org/apache/isis/security/shiro/authorization/AuthorizorShiro.java b/security/shiro/src/main/java/org/apache/isis/security/shiro/authorization/AuthorizorShiro.java
index 5ac6012..63f02a2 100644
--- a/security/shiro/src/main/java/org/apache/isis/security/shiro/authorization/AuthorizorShiro.java
+++ b/security/shiro/src/main/java/org/apache/isis/security/shiro/authorization/AuthorizorShiro.java
@@ -30,7 +30,7 @@ import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.OrderPrecedence;
-import org.apache.isis.core.security.authentication.Authentication;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.core.security.authentication.Authenticator;
 import org.apache.isis.core.security.authorization.Authorizor;
 import org.apache.isis.security.shiro.context.ShiroSecurityContext;
@@ -56,13 +56,13 @@ import lombok.val;
 public class AuthorizorShiro implements Authorizor {
 
     @Override
-    public boolean isVisible(final Authentication authentication, final Identifier identifier) {
-        return isPermitted(authentication.getUserName(), identifier, "r");
+    public boolean isVisible(final InteractionContext authentication, final Identifier identifier) {
+        return isPermitted(authentication.getUser().getName(), identifier, "r");
     }
 
     @Override
-    public boolean isUsable(final Authentication authentication, final Identifier identifier) {
-        return isPermitted(authentication.getUserName(), identifier, "w");
+    public boolean isUsable(final InteractionContext authentication, final Identifier identifier) {
+        return isPermitted(authentication.getUser().getName(), identifier, "w");
     }
 
     private boolean isPermitted(String userName, Identifier identifier, String qualifier) {
diff --git a/security/shiro/src/test/java/org/apache/isis/security/shiro/ShiroAuthenticatorOrAuthorizorTest_authenticate.java b/security/shiro/src/test/java/org/apache/isis/security/shiro/ShiroAuthenticatorOrAuthorizorTest_authenticate.java
index 9652236..75e7699 100644
--- a/security/shiro/src/test/java/org/apache/isis/security/shiro/ShiroAuthenticatorOrAuthorizorTest_authenticate.java
+++ b/security/shiro/src/test/java/org/apache/isis/security/shiro/ShiroAuthenticatorOrAuthorizorTest_authenticate.java
@@ -38,7 +38,6 @@ import org.apache.isis.applib.Identifier;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2.Mode;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.AuthenticationRequest;
 import org.apache.isis.core.security.authentication.AuthenticationRequestPassword;
 import org.apache.isis.security.shiro.authentication.AuthenticatorShiro;
@@ -61,7 +60,7 @@ public class ShiroAuthenticatorOrAuthorizorTest_authenticate {
 
         val configuration = new IsisConfiguration(null);
         configuration.getSecurity().getShiro().setAutoLogoutIfAlreadyAuthenticated(false);
-        
+
         authenticator = new AuthenticatorShiro(configuration);
         authorizor = new AuthorizorShiro();
     }
@@ -93,11 +92,11 @@ public class ShiroAuthenticatorOrAuthorizorTest_authenticate {
         assertThat(authenticator.canAuthenticate(AuthenticationRequestPassword.class), is(true));
 
         AuthenticationRequest ar = new AuthenticationRequestPassword("lonestarr", "vespa");
-        Authentication authentication = authenticator.authenticate(ar, "test code");
+        val authentication = authenticator.authenticate(ar, "test code");
 
         assertThat(authentication, is(not(nullValue())));
-        assertThat(authentication.getUserName(), is("lonestarr"));
-        assertThat(authentication.getValidationCode(), is("test code"));
+        assertThat(authentication.getUser().getName(), is("lonestarr"));
+        assertThat(authentication.getUser().getAuthenticationCode(), is("test code"));
 
         Identifier changeAddressIdentifier = Identifier.actionIdentifier(
                 TypeIdentifierTestFactory.customer(), "changeAddress", String.class, String.class);
@@ -116,6 +115,6 @@ public class ShiroAuthenticatorOrAuthorizorTest_authenticate {
         assertThat(authorizor.isVisible(authentication, cancelOrderIdentifier), is(false));
     }
 
-    
+
 
 }
diff --git a/security/shiro/src/test/java/org/apache/isis/security/shiro/ShiroAuthenticatorOrAuthorizorTest_isVisibleInAnyRole.java b/security/shiro/src/test/java/org/apache/isis/security/shiro/ShiroAuthenticatorOrAuthorizorTest_isVisibleInAnyRole.java
index f1d6bd6..79ea914 100644
--- a/security/shiro/src/test/java/org/apache/isis/security/shiro/ShiroAuthenticatorOrAuthorizorTest_isVisibleInAnyRole.java
+++ b/security/shiro/src/test/java/org/apache/isis/security/shiro/ShiroAuthenticatorOrAuthorizorTest_isVisibleInAnyRole.java
@@ -36,7 +36,6 @@ import org.apache.isis.applib.Identifier;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2.Mode;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.AuthenticationRequest;
 import org.apache.isis.core.security.authentication.AuthenticationRequestPassword;
 import org.apache.isis.security.shiro.authentication.AuthenticatorShiro;
@@ -59,7 +58,7 @@ public class ShiroAuthenticatorOrAuthorizorTest_isVisibleInAnyRole {
 
         val configuration = new IsisConfiguration(null);
         configuration.getSecurity().getShiro().setAutoLogoutIfAlreadyAuthenticated(false);
-        
+
         authenticator = new AuthenticatorShiro(configuration);
         authorizor = new AuthorizorShiro();
     }
@@ -82,7 +81,7 @@ public class ShiroAuthenticatorOrAuthorizorTest_isVisibleInAnyRole {
         SecurityUtils.setSecurityManager(securityManager);
 
         AuthenticationRequest ar = new AuthenticationRequestPassword("darkhelmet", "ludicrousspeed");
-        Authentication authentication = authenticator.authenticate(ar, "test code");
+        val authentication = authenticator.authenticate(ar, "test code");
 
         // when, then
         Identifier changeAddressIdentifier = Identifier.actionIdentifier(
@@ -99,7 +98,7 @@ public class ShiroAuthenticatorOrAuthorizorTest_isVisibleInAnyRole {
         SecurityUtils.setSecurityManager(securityManager);
 
         AuthenticationRequest ar = new AuthenticationRequestPassword("lonestarr", "vespa");
-        Authentication authentication = authenticator.authenticate(ar, "test code");
+        val authentication = authenticator.authenticate(ar, "test code");
 
         // when, then
         Identifier removeCustomerIdentifier = Identifier.actionIdentifier(
diff --git a/security/spring/src/main/java/org/apache/isis/security/spring/authentication/AuthenticatorSpring.java b/security/spring/src/main/java/org/apache/isis/security/spring/authentication/AuthenticatorSpring.java
index bfc254b..2a14761 100644
--- a/security/spring/src/main/java/org/apache/isis/security/spring/authentication/AuthenticatorSpring.java
+++ b/security/spring/src/main/java/org/apache/isis/security/spring/authentication/AuthenticatorSpring.java
@@ -27,7 +27,7 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
-import org.apache.isis.core.security.authentication.Authentication;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.core.security.authentication.AuthenticationProvider;
 import org.apache.isis.core.security.authentication.AuthenticationRequest;
 import org.apache.isis.core.security.authentication.Authenticator;
@@ -49,13 +49,13 @@ public class AuthenticatorSpring implements Authenticator {
     }
 
     @Override
-    public Authentication authenticate(final AuthenticationRequest request, final String code) {
+    public InteractionContext authenticate(final AuthenticationRequest request, final String code) {
         // SpringSecurityFilter should already have taken care of Authentication creation
         return authenticationProvider.currentAuthentication().orElse(null);
     }
 
     @Override
-    public void logout(final Authentication session) {
+    public void logout(final InteractionContext session) {
     }
 
 }
diff --git a/security/spring/src/main/java/org/apache/isis/security/spring/webmodule/SpringSecurityFilter.java b/security/spring/src/main/java/org/apache/isis/security/spring/webmodule/SpringSecurityFilter.java
index c61a119..3db1afd 100644
--- a/security/spring/src/main/java/org/apache/isis/security/spring/webmodule/SpringSecurityFilter.java
+++ b/security/spring/src/main/java/org/apache/isis/security/spring/webmodule/SpringSecurityFilter.java
@@ -32,20 +32,18 @@ import javax.servlet.http.HttpServletResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.core.context.SecurityContextHolder;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.user.UserMemento;
-import org.apache.isis.applib.services.iactnlayer.InteractionService;
+import org.apache.isis.applib.services.user.UserMemento.AuthenticationSource;
 import org.apache.isis.core.interaction.session.InteractionFactory;
-import org.apache.isis.core.security.authentication.Authentication;
-import org.apache.isis.core.security.authentication.standard.SimpleAuthentication;
 import org.apache.isis.security.spring.authconverters.AuthenticationConverter;
 
 import lombok.val;
-import lombok.extern.log4j.Log4j2;
 
 /**
  * @since 2.0 {@index}
  */
-@Log4j2
+//@Log4j2
 public class SpringSecurityFilter implements Filter {
 
     @Autowired private InteractionFactory interactionFactory;
@@ -83,16 +81,12 @@ public class SpringSecurityFilter implements Filter {
         }
 
         // TODO: this should be added by Wicket viewer
-        userMemento = userMemento.withRole("org.apache.isis.viewer.wicket.roles.USER");
+        userMemento = userMemento.withRoleAdded("org.apache.isis.viewer.wicket.roles.USER")
+                .withAuthenticationSource(AuthenticationSource.EXTERNAL);
 
-        val authentication = SimpleAuthentication.validOf(userMemento);
-        authentication.setType(Authentication.Type.EXTERNAL);
-
-        interactionFactory.runAuthenticated(
-                authentication,
-                ()->{
-                        filterChain.doFilter(servletRequest, servletResponse);
-                });
+        interactionFactory.run(
+                InteractionContext.ofUserWithSystemDefaults(userMemento),
+                ()->filterChain.doFilter(servletRequest, servletResponse));
     }
 
     @Inject List<AuthenticationConverter> converters;
diff --git a/viewers/restfulobjects/testing/src/main/java/org/apache/isis/viewer/restfulobjects/testing/ResourceContext_ensureCompatibleAcceptHeader_ContractTest.java b/viewers/restfulobjects/testing/src/main/java/org/apache/isis/viewer/restfulobjects/testing/ResourceContext_ensureCompatibleAcceptHeader_ContractTest.java
index 3eea3a4..861598d 100644
--- a/viewers/restfulobjects/testing/src/main/java/org/apache/isis/viewer/restfulobjects/testing/ResourceContext_ensureCompatibleAcceptHeader_ContractTest.java
+++ b/viewers/restfulobjects/testing/src/main/java/org/apache/isis/viewer/restfulobjects/testing/ResourceContext_ensureCompatibleAcceptHeader_ContractTest.java
@@ -18,9 +18,6 @@
  */
 package org.apache.isis.viewer.restfulobjects.testing;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -37,7 +34,11 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.springframework.web.context.WebApplicationContext;
 
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
 import org.apache.isis.applib.services.iactn.Interaction;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.core.interaction.session.InteractionFactory;
 import org.apache.isis.core.interaction.session.InteractionTracker;
@@ -45,7 +46,7 @@ import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.core.metamodel._testing.MetaModelContext_forTesting;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
-import org.apache.isis.core.security.authentication.Authentication;
+import org.apache.isis.core.security.authentication.InteractionContextFactory;
 import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
 import org.apache.isis.viewer.restfulobjects.applib.RestfulResponse.HttpStatusCode;
@@ -62,12 +63,13 @@ public abstract class ResourceContext_ensureCompatibleAcceptHeader_ContractTest
     @Rule public JUnitRuleMockery2 context =
             JUnitRuleMockery2.createFor(JUnitRuleMockery2.Mode.INTERFACES_AND_CLASSES);
 
+    protected final InteractionContext iaContext = InteractionContextFactory.testing();
+
     @Mock HttpHeaders mockHttpHeaders;
     @Mock HttpServletRequest mockHttpServletRequest;
     @Mock ServletContext mockServletContext;
     @Mock InteractionFactory mockInteractionFactory;
     @Mock Interaction mockInteraction;
-    @Mock Authentication mockAuthentication;
     @Mock SpecificationLoader mockSpecificationLoader;
     @Mock WebApplicationContext webApplicationContext;
     @Mock InteractionTracker mockIsisInteractionTracker;
@@ -82,7 +84,7 @@ public abstract class ResourceContext_ensureCompatibleAcceptHeader_ContractTest
 
         metaModelContext = MetaModelContext_forTesting.builder()
                 .specificationLoader(mockSpecificationLoader)
-                .authentication(mockAuthentication)
+                .authentication(iaContext)
                 .singleton(mockAuthenticationManager)
                 .singleton(mockIsisInteractionTracker)
                 .singleton(mockInteractionFactory)
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/HomePageReprRenderer.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/HomePageReprRenderer.java
index 81ab31f..67c06b4 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/HomePageReprRenderer.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/HomePageReprRenderer.java
@@ -20,10 +20,10 @@ package org.apache.isis.viewer.restfulobjects.viewer.resources;
 
 import java.util.stream.Stream;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
@@ -135,7 +135,7 @@ public class HomePageReprRenderer extends ReprRendererAbstract<HomePageReprRende
         getLinks().arrayAdd(link);
     }
 
-    private void addLinkToUser(Authentication authentication) {
+    private void addLinkToUser(InteractionContext authentication) {
         final JsonRepresentation link = LinkBuilder.newBuilder(
                 getResourceContext(),
                 Rel.USER.getName(),
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/UserReprRenderer.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/UserReprRenderer.java
index f26ace5..bd3fd38 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/UserReprRenderer.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/UserReprRenderer.java
@@ -18,7 +18,7 @@
  */
 package org.apache.isis.viewer.restfulobjects.viewer.resources;
 
-import org.apache.isis.core.security.authentication.Authentication;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
@@ -27,15 +27,15 @@ import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
 import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract;
 
-public class UserReprRenderer extends ReprRendererAbstract<UserReprRenderer, Authentication> {
+public class UserReprRenderer extends ReprRendererAbstract<UserReprRenderer, InteractionContext> {
 
     UserReprRenderer(final IResourceContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
         super(resourceContext, linkFollower, RepresentationType.USER, representation);
     }
 
     @Override
-    public UserReprRenderer with(final Authentication authentication) {
-        representation.mapPut("userName", authentication.getUserName());
+    public UserReprRenderer with(final InteractionContext authentication) {
+        representation.mapPut("userName", authentication.getUser().getName());
         final JsonRepresentation roles = JsonRepresentation.newArray();
 
         authentication.getUser().streamRoleNames()
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/IsisRestfulObjectsInteractionFilter.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/IsisRestfulObjectsInteractionFilter.java
index 1e5b1ae..8af2bce 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/IsisRestfulObjectsInteractionFilter.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/IsisRestfulObjectsInteractionFilter.java
@@ -19,8 +19,6 @@
 
 package org.apache.isis.viewer.restfulobjects.viewer.webmodule;
 
-import static org.apache.isis.commons.internal.base._With.requires;
-
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collection;
@@ -56,6 +54,8 @@ import org.apache.isis.core.webapp.modules.templresources.TemplateResourceCachin
 import org.apache.isis.viewer.restfulobjects.viewer.webmodule.auth.AuthenticationStrategy;
 import org.apache.isis.viewer.restfulobjects.viewer.webmodule.auth.AuthenticationStrategyDefault;
 
+import static org.apache.isis.commons.internal.base._With.requires;
+
 import lombok.val;
 
 /**
@@ -379,15 +379,13 @@ public class IsisRestfulObjectsInteractionFilter implements Filter {
 
                 authStrategy.bind(httpServletRequest, httpServletResponse, authentication);
 
-                interactionFactory.runAuthenticated(
+                interactionFactory.run(
                         authentication,
                         ()->{
-
                             transactionService.runWithinCurrentTransactionElseCreateNew(()->
                                 chain.doFilter(request, response))
                             .mapFailure(e->new TransactionalException("", e))
                             .optionalElseFail();
-
                         });
 
                 return;
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategy.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategy.java
index d73ec21..635881e 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategy.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategy.java
@@ -22,27 +22,27 @@ package org.apache.isis.viewer.restfulobjects.viewer.webmodule.auth;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.isis.core.security.authentication.Authentication;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
 
 /**
  * Decouples the <code>IsisRestfulObjectsInteractionFilter</code> from the mechanism of obtaining the
- * {@link Authentication}.
+ * {@link InteractionContext}.
  *
  * @since 2.0 {@index}
  */
 public interface AuthenticationStrategy {
 
     /**
-     * Returns a still-valid {@link Authentication} or {@code null}
-     * @see AuthenticationManager#isSessionValid(Authentication)
+     * Returns a still-valid {@link InteractionContext} or {@code null}
+     * @see AuthenticationManager#isSessionValid(InteractionContext)
      */
-    Authentication lookupValid(
+    InteractionContext lookupValid(
             HttpServletRequest httpServletRequest,
             HttpServletResponse httpServletResponse);
 
     /**
-     * Binds the request to a still-valid {@link Authentication} if applicable
+     * Binds the request to a still-valid {@link InteractionContext} if applicable
      * @param httpServletRequest
      * @param httpServletResponse
      * @param auth
@@ -50,7 +50,7 @@ public interface AuthenticationStrategy {
     void bind(
             HttpServletRequest httpServletRequest,
             HttpServletResponse httpServletResponse,
-            Authentication auth);
+            InteractionContext auth);
 
     void invalidate(
             HttpServletRequest httpServletRequest,
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategyAbstract.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategyAbstract.java
index d0a8396..18d73b6 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategyAbstract.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategyAbstract.java
@@ -36,7 +36,8 @@ import lombok.val;
  *
  * @since 2.0 {@index}
  */
-public abstract class AuthenticationStrategyAbstract implements AuthenticationStrategy {
+public abstract class AuthenticationStrategyAbstract
+implements AuthenticationStrategy {
 
     public static final int STATUS_UNAUTHORIZED = 401;
 
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategyBasicAuth.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategyBasicAuth.java
index 8b3ff3d..8af2bc4 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategyBasicAuth.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategyBasicAuth.java
@@ -26,16 +26,16 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.commons.internal.base._Bytes;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.core.security.authentication.AuthenticationRequestPassword;
-import org.apache.isis.core.security.authentication.Authentication;
 
 import lombok.val;
 
 /**
  * Implements the HTTP Basic Auth protocol; does not bind the
- * {@link Authentication} onto the {@link HttpSession}.
+ * {@link InteractionContext} onto the {@link HttpSession}.
  *
  * @since 2.0 {@index}
  */
@@ -47,7 +47,7 @@ public class AuthenticationStrategyBasicAuth extends AuthenticationStrategyAbstr
     private static Pattern USER_AND_PASSWORD_REGEX = Pattern.compile("^(.+):(.+)$");
 
     @Override
-    public Authentication lookupValid(
+    public InteractionContext lookupValid(
             final HttpServletRequest httpServletRequest,
             final HttpServletResponse httpServletResponse) {
 
@@ -83,7 +83,7 @@ public class AuthenticationStrategyBasicAuth extends AuthenticationStrategyAbstr
     public void bind(
             HttpServletRequest httpServletRequest,
             HttpServletResponse httpServletResponse,
-            Authentication auth) {
+            InteractionContext auth) {
         // TODO Auto-generated method stub
 
     }
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategyDefault.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategyDefault.java
index d4afca3..66b422d 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategyDefault.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/auth/AuthenticationStrategyDefault.java
@@ -23,13 +23,13 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
-import org.apache.isis.core.security.authentication.Authentication;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 
 import lombok.val;
 
 /**
- * Returns a valid {@link Authentication} through a number of mechanisms;
- * supports caching of the {@link Authentication} onto the
+ * Returns a valid {@link InteractionContext} through a number of mechanisms;
+ * supports caching of the {@link InteractionContext} onto the
  * {@link HttpSession}.
  *
  * <p>
@@ -41,12 +41,13 @@ import lombok.val;
  *
  * @since 2.0 {@index}
  */
-public class AuthenticationStrategyDefault extends AuthenticationStrategyAbstract {
+public class AuthenticationStrategyDefault
+extends AuthenticationStrategyAbstract {
 
     public static final String HTTP_SESSION_AUTHENTICATION_SESSION_KEY = AuthenticationStrategyDefault.class.getPackage().getName() + ".authentication";
 
     @Override
-    public Authentication lookupValid(
+    public InteractionContext lookupValid(
             final HttpServletRequest httpServletRequest,
             final HttpServletResponse httpServletResponse) {
 
@@ -54,7 +55,7 @@ public class AuthenticationStrategyDefault extends AuthenticationStrategyAbstrac
         val httpSession = getHttpSession(httpServletRequest);
 
         // use previously authenticated session if available
-        val authentication = (Authentication)
+        val authentication = (InteractionContext)
                 httpSession.getAttribute(HTTP_SESSION_AUTHENTICATION_SESSION_KEY);
         if (authentication != null) {
             val sessionValid = authenticationManager.isSessionValid(authentication);
@@ -70,7 +71,7 @@ public class AuthenticationStrategyDefault extends AuthenticationStrategyAbstrac
     public void bind(
             final HttpServletRequest httpServletRequest,
             final HttpServletResponse httpServletResponse,
-            final Authentication authentication) {
+            final InteractionContext authentication) {
 
         val httpSession = getHttpSession(httpServletRequest);
         if(authentication != null) {
diff --git a/viewers/restfulobjects/viewer/src/test/java/org/apache/isis/viewer/restfulobjects/viewer/context/ResourceContext_getArg_Test.java b/viewers/restfulobjects/viewer/src/test/java/org/apache/isis/viewer/restfulobjects/viewer/context/ResourceContext_getArg_Test.java
index 6cd8f87..c90112d 100644
--- a/viewers/restfulobjects/viewer/src/test/java/org/apache/isis/viewer/restfulobjects/viewer/context/ResourceContext_getArg_Test.java
+++ b/viewers/restfulobjects/viewer/src/test/java/org/apache/isis/viewer/restfulobjects/viewer/context/ResourceContext_getArg_Test.java
@@ -18,9 +18,6 @@
  */
 package org.apache.isis.viewer.restfulobjects.viewer.context;
 
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.MatcherAssert.assertThat;
-
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 
@@ -31,6 +28,9 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.springframework.web.context.WebApplicationContext;
 
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+
 import org.apache.isis.commons.internal.codec._UrlDecoderUtil;
 import org.apache.isis.core.interaction.session.InteractionFactory;
 import org.apache.isis.core.interaction.session.InteractionTracker;
@@ -40,7 +40,6 @@ import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2.Mode;
 import org.apache.isis.core.metamodel._testing.MetaModelContext_forTesting;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
@@ -58,7 +57,6 @@ public class ResourceContext_getArg_Test {
     @Mock private InteractionFactory mockInteractionFactory;
     @Mock private InteractionTracker mockIsisInteractionTracker;
     @Mock private AuthenticationManager mockAuthenticationManager;
-    @Mock private Authentication mockAuthentication;
     @Mock private SpecificationLoader mockSpecificationLoader;
     @Mock private WebApplicationContext webApplicationContext;
 
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis.java
index 2009a7e..d0fe946 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis.java
@@ -29,13 +29,14 @@ import org.apache.wicket.request.cycle.RequestCycle;
 
 import org.apache.isis.applib.clock.VirtualClock;
 import org.apache.isis.applib.services.clock.ClockService;
+import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.session.SessionLoggingService;
+import org.apache.isis.applib.services.user.UserMemento;
+import org.apache.isis.applib.services.user.UserMemento.AuthenticationSource;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.interaction.session.InteractionFactory;
-import org.apache.isis.core.interaction.session.InteractionTracker;
 import org.apache.isis.core.runtime.context.IsisAppCommonContext;
 import org.apache.isis.core.runtime.context.IsisAppCommonContext.HasCommonContext;
-import org.apache.isis.core.security.authentication.Authentication;
 import org.apache.isis.core.security.authentication.AuthenticationRequestPassword;
 import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
 import org.apache.isis.viewer.wicket.model.models.BookmarkedPagesModel;
@@ -72,7 +73,7 @@ implements BreadcrumbModelProvider, BookmarkedPagesModelProvider, HasCommonConte
     /**
      * As populated in {@link #signIn(String, String)}.
      */
-    private Authentication authentication;
+    private InteractionContext authentication;
 
     public AuthenticatedWebSessionForIsis(Request request) {
         super(request);
@@ -133,20 +134,22 @@ implements BreadcrumbModelProvider, BookmarkedPagesModelProvider, HasCommonConte
 
         String userName = null;
         if (getAuthentication() != null) {
-            userName = getAuthentication().getUserName();
+            userName = getAuthentication().getUser().getName();
         }
 
         log(SessionLoggingService.Type.LOGOUT, userName, causedBy);
     }
 
-    public synchronized Authentication getAuthentication() {
+    public synchronized InteractionContext getAuthentication() {
 
-        commonContext.getInteractionTracker().currentAuthentication()
+        commonContext.getInteractionTracker().currentInteractionContext()
         .ifPresent(currentAuthentication->{
 
             if (getAuthenticationManager().isSessionValid(currentAuthentication)) {
                 if (this.authentication != null) {
-                    if (Objects.equals(currentAuthentication.getUserName(), this.authentication.getUserName())) {
+                    if (Objects.equals(
+                            currentAuthentication.getUser().getName(),
+                            this.authentication.getUser().getName())) {
                         // ok, same session so far as Wicket is concerned
                         if (isSignedIn()) {
                             // nothing to do...
@@ -179,13 +182,13 @@ implements BreadcrumbModelProvider, BookmarkedPagesModelProvider, HasCommonConte
 
     /**
      * This is a no-op if the {@link #getAuthentication() authentication session}'s
-     * {@link Authentication#getType() type} is
-     * {@link org.apache.isis.core.security.authentication.Authentication.Type#EXTERNAL external}
+     * {@link UserMemento#getAuthenticationSource() source} is
+     * {@link AuthenticationSource#EXTERNAL external}
      * (eg as managed by keycloak).
      */
     @Override
     public void invalidate() {
-        if(this.authentication.getType() == Authentication.Type.EXTERNAL) {
+        if(this.authentication.getUser().getAuthenticationSource().isExternal()) {
             return;
         }
         // otherwise
diff --git a/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis_Authenticate.java b/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis_Authenticate.java
index bb1a2a0..f84cd82 100644
--- a/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis_Authenticate.java
+++ b/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis_Authenticate.java
@@ -29,10 +29,15 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+
+import org.apache.isis.applib.services.iactnlayer.ThrowingRunnable;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.applib.services.session.SessionLoggingService;
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.applib.services.iactnlayer.ThrowingRunnable;
 import org.apache.isis.core.interaction.session.InteractionFactory;
 import org.apache.isis.core.interaction.session.InteractionTracker;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
@@ -40,16 +45,11 @@ import org.apache.isis.core.runtime.context.IsisAppCommonContext;
 import org.apache.isis.core.security.authentication.AuthenticationRequest;
 import org.apache.isis.core.security.authentication.AuthenticationRequestPassword;
 import org.apache.isis.core.security.authentication.Authenticator;
+import org.apache.isis.core.security.authentication.InteractionContextFactory;
 import org.apache.isis.core.security.authentication.manager.AnonymousInteractionFactory;
 import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
-import org.apache.isis.core.security.authentication.singleuser.SingleUserAuthentication;
 import org.apache.isis.core.security.authentication.standard.RandomCodeGeneratorDefault;
 
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.nullValue;
-
 public class AuthenticatedWebSessionForIsis_Authenticate {
 
 
@@ -89,11 +89,11 @@ public class AuthenticatedWebSessionForIsis_Authenticate {
                 allowing(mockCommonContext).getInteractionTracker();
                 will(returnValue(mockInteractionTracker));
 
-                allowing(mockInteractionTracker).currentAuthentication();
-                will(returnValue(Optional.of(new SingleUserAuthentication())));
+                allowing(mockInteractionTracker).currentInteractionContext();
+                will(returnValue(Optional.of(InteractionContextFactory.testing())));
 
                 allowing(mockInteractionFactory)
-                .runAuthenticated(with(new SingleUserAuthentication()), with(any(ThrowingRunnable.class)));
+                .run(with(InteractionContextFactory.testing()), with(any(ThrowingRunnable.class)));
 
                 allowing(mockInteractionFactory)
                 .runAnonymous(with(any(ThrowingRunnable.class)));
@@ -136,7 +136,7 @@ public class AuthenticatedWebSessionForIsis_Authenticate {
                 oneOf(mockAuthenticator).canAuthenticate(AuthenticationRequestPassword.class);
                 will(returnValue(true));
                 oneOf(mockAuthenticator).authenticate(with(any(AuthenticationRequest.class)), with(any(String.class)));
-                will(returnValue(new SingleUserAuthentication()));
+                will(returnValue(InteractionContextFactory.testing()));
             }
         });
 
diff --git a/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis_SignIn.java b/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis_SignIn.java
index 78e0d52..470331f 100644
--- a/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis_SignIn.java
+++ b/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis_SignIn.java
@@ -29,33 +29,33 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import org.apache.isis.applib.services.iactnlayer.ThrowingRunnable;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.applib.services.session.SessionLoggingService;
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.applib.services.iactnlayer.ThrowingRunnable;
 import org.apache.isis.core.interaction.session.InteractionFactory;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.core.runtime.context.IsisAppCommonContext;
 import org.apache.isis.core.security.authentication.AuthenticationRequest;
 import org.apache.isis.core.security.authentication.AuthenticationRequestPassword;
 import org.apache.isis.core.security.authentication.Authenticator;
+import org.apache.isis.core.security.authentication.InteractionContextFactory;
 import org.apache.isis.core.security.authentication.manager.AnonymousInteractionFactory;
 import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
-import org.apache.isis.core.security.authentication.singleuser.SingleUserAuthentication;
 import org.apache.isis.core.security.authentication.standard.RandomCodeGeneratorDefault;
 
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
-
 public class AuthenticatedWebSessionForIsis_SignIn {
 
     @Rule
     public final JUnitRuleMockery2 context =
             JUnitRuleMockery2.createFor(JUnitRuleMockery2.Mode.INTERFACES_AND_CLASSES);
 
-    @Mock
-    protected Request mockRequest;
     private AuthenticationManager authMgr;
+
+    @Mock protected Request mockRequest;
     @Mock protected Authenticator mockAuthenticator;
     @Mock protected IsisAppCommonContext mockCommonContext;
     @Mock protected InteractionFactory mockInteractionFactory;
@@ -85,7 +85,7 @@ public class AuthenticatedWebSessionForIsis_SignIn {
                 will(returnValue(mockInteractionFactory));
 
                 allowing(mockInteractionFactory)
-                .runAuthenticated(with(new SingleUserAuthentication()), with(any(ThrowingRunnable.class)));
+                .run(with(InteractionContextFactory.testing()), with(any(ThrowingRunnable.class)));
 
                 allowing(mockInteractionFactory)
                 .runAnonymous(with(any(ThrowingRunnable.class)));
@@ -101,7 +101,9 @@ public class AuthenticatedWebSessionForIsis_SignIn {
 
                 oneOf(mockAuthenticator).canAuthenticate(AuthenticationRequestPassword.class);
                 will(returnValue(true));
+
                 oneOf(mockAuthenticator).authenticate(with(any(AuthenticationRequest.class)), with(any(String.class)));
+                will(returnValue(InteractionContextFactory.testing()));
             }
         });
 
diff --git a/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis_TestAbstract.java b/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis_TestAbstract.java
index bc51387..239da8b 100644
--- a/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis_TestAbstract.java
+++ b/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis_TestAbstract.java
@@ -27,15 +27,15 @@ import org.jmock.Expectations;
 import org.jmock.auto.Mock;
 import org.junit.Rule;
 
+import org.apache.isis.applib.services.iactnlayer.ThrowingRunnable;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.applib.services.session.SessionLoggingService;
-import org.apache.isis.applib.services.iactnlayer.ThrowingRunnable;
 import org.apache.isis.core.interaction.session.InteractionFactory;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2.Mode;
 import org.apache.isis.core.runtime.context.IsisAppCommonContext;
+import org.apache.isis.core.security.authentication.InteractionContextFactory;
 import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
-import org.apache.isis.core.security.authentication.singleuser.SingleUserAuthentication;
 
 public abstract class AuthenticatedWebSessionForIsis_TestAbstract {
 
@@ -62,7 +62,9 @@ public abstract class AuthenticatedWebSessionForIsis_TestAbstract {
                 allowing(mockCommonContext).lookupServiceElseFail(InteractionFactory.class);
                 will(returnValue(mockInteractionFactory));
 
-                allowing(mockInteractionFactory).runAuthenticated(new SingleUserAuthentication(), with(any(ThrowingRunnable.class)));
+                allowing(mockInteractionFactory).run(
+                        InteractionContextFactory.testing(),
+                        with(any(ThrowingRunnable.class)));
                 // ignore
 
                 // must provide explicit expectation, since Locale is final.