diff --git a/pom.xml b/pom.xml
index 76386fdaa560a58fd9750b3fc04f3ac6a00a35e3..9888107480ccb9ca0cb3a4c117af652820303740 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>edu.wisc.uwss</groupId>
 	<artifactId>uw-spring-security</artifactId>
-	<version>1.1.1-SNAPSHOT</version>
+	<version>1.2.0-SNAPSHOT</version>
 	<packaging>pom</packaging>
 	<name>UW Spring Security Parent</name>
 	<description>Parent project for module to integrate Spring Security with UW authentication mechanism.</description>
diff --git a/uw-spring-security-config/pom.xml b/uw-spring-security-config/pom.xml
index 150d1ecfd237c1205bc7581e05ff35f11a80abb4..093d2a150c5d28e4e813680489bba54bb5d69e2f 100644
--- a/uw-spring-security-config/pom.xml
+++ b/uw-spring-security-config/pom.xml
@@ -3,7 +3,7 @@
 	<parent>
 		<groupId>edu.wisc.uwss</groupId>
 		<artifactId>uw-spring-security</artifactId>
-		<version>1.1.1-SNAPSHOT</version>
+		<version>1.2.0-SNAPSHOT</version>
 	</parent>
 	<artifactId>uw-spring-security-config</artifactId>
 	<name>UW Spring Security Configuration</name>
diff --git a/uw-spring-security-core/pom.xml b/uw-spring-security-core/pom.xml
index ad1f4aa3bbb79b707c4b5c26aad5dbcc445fc204..01f3d8fa31f2d44be1339af208d431b604cdaa0f 100644
--- a/uw-spring-security-core/pom.xml
+++ b/uw-spring-security-core/pom.xml
@@ -3,7 +3,7 @@
 	<parent>
 		<groupId>edu.wisc.uwss</groupId>
 		<artifactId>uw-spring-security</artifactId>
-		<version>1.1.1-SNAPSHOT</version>
+		<version>1.2.0-SNAPSHOT</version>
 	</parent>
 	<artifactId>uw-spring-security-core</artifactId>
 	<name>UW Spring Security Core</name>
diff --git a/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsAttributesMapper.java b/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsAttributesMapper.java
index db33acb8ca0dec3febf7d977069fd6220928c49c..751cde911439b9ef23622a5ead0e4d4fa88b617b 100644
--- a/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsAttributesMapper.java
+++ b/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsAttributesMapper.java
@@ -13,6 +13,15 @@ import edu.wisc.uwss.UWUserDetailsImpl;
 /**
  * Interface providing a mechanism to bind a row from the local users properties
  * file to a {@link UWUserDetails} instance.
+ *
+ * This interface is used during application initialization - not during
+ * authentication attempts. Since it is executed during Spring ApplicationContext initialization,
+ * implementations should avoid injecting other service or dao interfaces, as it may be
+ * affected by a race condition.
+ *
+ * If you have custom {@link UWUserDetails} that depend on services/daos to complete the model,
+ * you may want to consider implementing a {@link LocalUsersAuthenticationAttemptCallback}; that interface
+ * participates in the authentication attempt itself, not during application initialization.
  * 
  * @author Nicholas Blair
  */
diff --git a/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsManagerImpl.java b/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsManagerImpl.java
index 9985a05c0f0ffdbd1f6b4a0dbb54bbfb4f97a6a7..e331dae10c6dbe349f90f5cf604c0aa6ffa49f3d 100644
--- a/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsManagerImpl.java
+++ b/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsManagerImpl.java
@@ -3,6 +3,8 @@
  */
 package edu.wisc.uwss.local;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
@@ -39,6 +41,8 @@ public class LocalUserDetailsManagerImpl implements UserDetailsManager {
   private Logger logger = LoggerFactory.getLogger(this.getClass());
   private final Map<String, UWUserDetails> users = new ConcurrentHashMap<>();
 
+  @Autowired(required=false)
+  private List<LocalUsersAuthenticationAttemptCallback> callbacks = new ArrayList<>();
   @Autowired(required=false)
   private LocalUserDetailsAttributesMapper localUserDetailsAttributeMapper = new LocalUserDetailsAttributesMapper.Default();
 
@@ -68,6 +72,16 @@ public class LocalUserDetailsManagerImpl implements UserDetailsManager {
   public void setDemoUsers(@Qualifier("demo-users") Properties properties) {
    this.properties = properties;
   }
+
+  /**
+   * Visible for testing.
+   *
+   * @param callbacks
+   */
+  void setCallbacks(List<LocalUsersAuthenticationAttemptCallback> callbacks) {
+    this.callbacks = callbacks;
+  }
+
   /**
    * Add a user. Does nothing if the argument is null or the {@link UWUserDetailsImpl#getUsername()} is blank.
    * 
@@ -109,7 +123,11 @@ public class LocalUserDetailsManagerImpl implements UserDetailsManager {
     if(user == null) {
       throw new UsernameNotFoundException(username + " not found");
     }
-    return SerializationUtils.clone(user);
+    UWUserDetails result = SerializationUtils.clone(user);
+    for(LocalUsersAuthenticationAttemptCallback callback: callbacks) {
+      callback.success(result);
+    }
+    return result;
   }
   /**
    * @param user
diff --git a/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUsersAuthenticationAttemptCallback.java b/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUsersAuthenticationAttemptCallback.java
new file mode 100644
index 0000000000000000000000000000000000000000..f862109e514a70df950f2ec50cf246bc3486d209
--- /dev/null
+++ b/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUsersAuthenticationAttemptCallback.java
@@ -0,0 +1,39 @@
+package edu.wisc.uwss.local;
+
+import edu.wisc.uwss.UWUserDetails;
+
+/**
+ * Callback interface allowing downstream projects to mutate the {@link UWUserDetails} returned
+ * by {@link LocalUserDetailsManagerImpl#loadUserByUsername(String)} during an authentication attempt.
+ *
+ * Example usage:
+ *
+ <pre>
+ class MyLocalUsersAuthenticationAttemptCallback implements LocalUsersAuthenticationAttemptCallback<MyUWUserDetailsImpl> {
+
+   @Autowired
+   private MySomethingDao somethingDao;
+
+   public void success(MyUWUserDetailsImpl userDetails) {
+     userDetails.setMySomethingField(somethingDao.getSomethingsForUser(userDetails.getUsername());
+   }
+ }
+ </pre>
+ *
+ * Consumers can register any number of Beans implementing this interface; see {@link org.springframework.core.Ordered}
+ * if you need a particular order of execution.
+ *
+ * If instead you need to modify {@link UWUserDetails} instances during application initialization only,
+ * see {@link LocalUserDetailsAttributesMapper}.
+ *
+ * @author Nicholas Blair
+ */
+public interface LocalUsersAuthenticationAttemptCallback<T extends UWUserDetails> {
+
+  /**
+   * Callback executed upon successfully loading the {@link UWUserDetails} for a username.
+   *
+   * @param userDetails the userDetails to modify
+   */
+  void success(T userDetails);
+}
diff --git a/uw-spring-security-core/src/main/java/edu/wisc/uwss/preauth/PreauthenticatedUserDetailsAttributeMapper.java b/uw-spring-security-core/src/main/java/edu/wisc/uwss/preauth/PreauthenticatedUserDetailsAttributeMapper.java
index 7684fdaf1683b580424367149836fdb83a2d0036..1dce635642ffcb9a533393cce02c841703488bc8 100644
--- a/uw-spring-security-core/src/main/java/edu/wisc/uwss/preauth/PreauthenticatedUserDetailsAttributeMapper.java
+++ b/uw-spring-security-core/src/main/java/edu/wisc/uwss/preauth/PreauthenticatedUserDetailsAttributeMapper.java
@@ -23,6 +23,9 @@ import edu.wisc.uwss.UWUserDetailsImpl;
 /**
  * Interface providing a mechanism to the attributes preauthenticated in the
  * {@link HttpServletRequest} to a {@link UWUserDetails} instance.
+ *
+ * This interface is executed during authentication attempts (similar to
+ * {@link edu.wisc.uwss.local.LocalUsersAuthenticationAttemptCallback}).
  * 
  * @author Nicholas Blair
  */
diff --git a/uw-spring-security-core/src/test/java/edu/wisc/uwss/local/LocalUserDetailsManagerImplTest.java b/uw-spring-security-core/src/test/java/edu/wisc/uwss/local/LocalUserDetailsManagerImplTest.java
index b07c9e6d07efa3b0d31f85b7dee2e8da3e3bbfb5..405ccf609aec0c379cb73b5128f3f0f34fbacc3d 100644
--- a/uw-spring-security-core/src/test/java/edu/wisc/uwss/local/LocalUserDetailsManagerImplTest.java
+++ b/uw-spring-security-core/src/test/java/edu/wisc/uwss/local/LocalUserDetailsManagerImplTest.java
@@ -10,6 +10,7 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Properties;
 
@@ -30,7 +31,7 @@ import edu.wisc.uwss.UWUserDetailsImpl;
 public class LocalUserDetailsManagerImplTest {
 
   /**
-   * Verify {@link LocalUserDetailsServiceImpl#loadUserByUsername(String)} throws 
+   * Verify {@link LocalUserDetailsManagerImpl#loadUserByUsername(String)} throws
    * {@link UsernameNotFoundException} for an unknown user.
    */
   @Test(expected=UsernameNotFoundException.class)
@@ -275,5 +276,32 @@ public class LocalUserDetailsManagerImplTest {
     manager.deleteUser(username);
     assertFalse(manager.userExists(username));
   }
+
+  /**
+   * Test confirming {@link LocalUsersAuthenticationAttemptCallback} is fired appropriately
+   * during an authentication attempt ({@link LocalUserDetailsManagerImpl#loadUserByUsername(String)}).
+   */
+  @Test
+  public void loadUserByUsername_with_callback() {
+    LocalUserDetailsManagerImpl manager = new LocalUserDetailsManagerImpl();
+    // setup a simple callback to mutate the userDetails
+    LocalUsersAuthenticationAttemptCallback callback = new LocalUsersAuthenticationAttemptCallback<UWUserDetailsImpl>() {
+      @Override
+      public void success(UWUserDetailsImpl userDetails) {
+        userDetails.setFirstName("something custom");
+      }
+    };
+    manager.setCallbacks(Arrays.asList(callback));
+
+    // no first name set on original user
+    UWUserDetails user = new UWUserDetailsImpl("UW000A000", "foo", "bar", "Foo Bar", "foo@foo.wisc.edu");
+    // first name starts null
+    assertNull(user.getFirstName());
+    manager.addDemoUser(user);
+
+    UWUserDetails result = manager.loadUserByUsername("foo");
+    // observe firstname modified by the callback
+    assertEquals("something custom", result.getFirstName());
+  }
 }
   
\ No newline at end of file
diff --git a/uw-spring-security-sample-war/pom.xml b/uw-spring-security-sample-war/pom.xml
index dd52b4756ae52f916f101252e1ac6b9f8e8cf6c0..be90c32fad2a3b16c226e0ebd3f6871bb74d7131 100644
--- a/uw-spring-security-sample-war/pom.xml
+++ b/uw-spring-security-sample-war/pom.xml
@@ -3,7 +3,7 @@
 	<parent>
 		<groupId>edu.wisc.uwss</groupId>
 		<artifactId>uw-spring-security</artifactId>
-		<version>1.1.1-SNAPSHOT</version>
+		<version>1.2.0-SNAPSHOT</version>
 	</parent>
 	<artifactId>uw-spring-security-sample-war</artifactId>
 	<name>UW Spring Security Sample War</name>
diff --git a/uw-spring-security-web/pom.xml b/uw-spring-security-web/pom.xml
index 4db1c09a5f0cb2f6f93b72b9d162c1e0b8af71e2..4f9a7f95b9d22a2d634356213479b3b006707e87 100644
--- a/uw-spring-security-web/pom.xml
+++ b/uw-spring-security-web/pom.xml
@@ -3,7 +3,7 @@
 	<parent>
 		<groupId>edu.wisc.uwss</groupId>
 		<artifactId>uw-spring-security</artifactId>
-		<version>1.1.1-SNAPSHOT</version>
+		<version>1.2.0-SNAPSHOT</version>
 	</parent>
 	<artifactId>uw-spring-security-web</artifactId>
 	<name>UW Spring Security Web</name>