Auth.getCurrentUser returns user sub even if user logged in with email
Before opening, please confirm:
- [x] I have searched for duplicate or closed issues and discussions.
Language and Async Model
Java
Amplify Categories
Authentication
Gradle script dependencies
def aws_amplify_version = '2.30.1'
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
implementation "com.amplifyframework:aws-api:$aws_amplify_version"
implementation "com.amplifyframework:aws-auth-cognito:$aws_amplify_version"
implementation "com.amplifyframework:core:$aws_amplify_version"
Environment information
------------------------------------------------------------
Gradle 8.14.2
------------------------------------------------------------
Build time: 2025-06-05 13:32:01 UTC
Revision: 30db2a3bdfffa9f8b40e798095675f9dab990a9a
Kotlin: 2.0.21
Groovy: 3.0.24
Ant: Apache Ant(TM) version 1.10.15 compiled on August 25 2024
Launcher JVM: 17.0.12 (Oracle Corporation 17.0.12+8-LTS-286)
Daemon JVM: E:\Programare\jdk-17.0.12 (no JDK specified, using current Java home)
OS: Windows 11 10.0 amd64
Please include any relevant guides or documentation you're referencing
No response
Describe the bug
Auth.getCurrentUser returns user sub even if user logged in with email.
The AWS Mobile Client was returning the email in such cases. The javadoc said:
/**
* Returns the username attribute of the current access token. Note that the value stored in the username
* attribute of the access token may vary depending on how sign-in was performed. For example, if the user signed in
* with email, the username attribute will have the email address.
* @return The username attribute of the current access token.
* @see <a href="https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html#amazon-cognito-user-pools-using-the-access-token">Using the Access Token</a>
* from Cognito documentation.
*/
@AnyThread
public String getUsername() {
try {
if (userpoolsLoginKey.equals(mStore.get(PROVIDER_KEY))) {
return userpool.getCurrentUser().getUserId();
}
return null;
} catch (Exception e) {
return null;
}
}
Reproduction steps (if applicable)
No response
Code Snippet
CompletableFuture<String> future = new CompletableFuture<>();
Amplify.Auth.getCurrentUser(
user -> future.complete(user.getUsername()),
authException -> future.complete(null)
);
Both the user id and the username attributes in AuthUser are the user sub, regardless of how the user logged in.
Log output
// Put your logs below this line
Configuration File
No response
GraphQL Schema
// Put your schema below this line
Additional information and screenshots
No response
HI @faltiska. I believe this is the intended behavior for Amplify, but I'll look into it and get back to you. I'm marking this as a feature request for now.
Hi @faltiska I have some more context to share about this. It looks like this was an intentional decision in Amplify to return the username as it appears in the tokens issued by Cognito. When you sign in with an email the tokens issued by Cognito will have the username claim set to be equal to the user's sub - and indeed you can confirm in the Cognito console that is what their username is set to.
In the AWS SDK things worked a little bit differently, the AWSMobileClient would store the value used to sign in in shared preferences (see here) and then later return that as the username from the function you highlighted in the issue.
Amplify could ultimately do something similar and store the sign in ID together with the credentials, but that is not how it works today. I'll leave this open as a feature request to gather community feedback on the utility of this change. In the meantime I would suggest using the getUserAttributes API to retrieve the email address of the user.
I do have a simple workaround. I am currently getting the email from the ID token, at login. The method to get the ID Token may be going over the network, which I wanted to avoid. So I am also storing the email it in Preferences, at login, so I can quickly access it later. This is simple enough.
But let me still try to make an argument against the decision to return the user's sub.
The definition of username is "an identification used by a person with access to a computer, network, or online service." And, since the AuthUser has both a userId and a username, it emphasizes the expectation that the username is something different than than the user id.
Even the AuthUser constructor javadoc agrees:
/**
* Object to represent a logged in user with its locally cached attributes.
* @param userId A unique identifier for this user
* @param username The username used for logging in
*/
public AuthUser(@NonNull String userId, @NonNull String username) {
this.userId = Objects.requireNonNull(userId);
this.username = Objects.requireNonNull(username);
}
I agree. This decision was made before my time and I don't have a lot of additional context on what the reasoning was. We cannot change the username value at this point as it would potentially be a breaking change, but there are several other options for how we could surface this information. Let me chat about this with the team and get back to you.