Accounts with Cognito
Register and sign in users and obtain scoped AWS credentials.
Use a User Pool for player accounts. Add an Identity Pool when those players need temporary AWS credentials for services such as S3 or DynamoDB.
Setup
In Project Settings → Betide → Crossplay → AWS Cognito, set:
| Setting | Value |
|---|---|
| User Pool Id | Your Cognito user pool ID |
| User Pool Client Id | An app client created without a client secret |
| Identity Pool Id | Optional pool configured to trust that user pool and app client |
Match the AWS region and credential source to your resources. Enable the app client’s auth flow for your chosen login method: ALLOW_USER_SRP_AUTH for SRP or ALLOW_USER_PASSWORD_AUTH for password login. AWS auth flows
Keep refresh-token rotation disabled and enable ALLOW_REFRESH_TOKEN_AUTH: the plugin refreshes sessions through that flow. AWS refresh requirements
Register and confirm
Enable self-registration and configure the pool’s required attributes and message delivery. Registration does not sign the player in. For a pool requiring confirmation, collect its code before login.
Register with an email address
Loading the interactive viewer.
Confirm the player account
Loading the interactive viewer.
Resend the confirmation code
Loading the interactive viewer.
Game module dependencies: AWSIKCognito, BetideCore, Engine. The account provider also works without UCIK.
#include "Engine/GameInstance.h"
#include "AWSIKCognito.h"
#include "Accounts/IUCIKAccountProvider.h"
FBetideCallbackVoid AccountCompletion(UGameInstance &GameInstance, FString SuccessMessage)
{
return FBetideCallbackVoid::CreateWeakLambda(
&GameInstance,
[SuccessMessage = MoveTemp(SuccessMessage)](const TBetideResult<void> &Result) {
if (!Result.bOk)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("%s"), *Result.Error.Message);
return;
}
UE_LOG(LogAWSIKCognito, Log, TEXT("%s"), *SuccessMessage);
});
}
void CreatePlayerAccount(UGameInstance &GameInstance, const FString &Username,
const FString &Password, const FString &Email)
{
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
FUCIKAccountAttribute EmailAttribute;
EmailAttribute.Name = TEXT("email");
EmailAttribute.Value = Email;
Accounts->Register(Username, Password, {EmailAttribute},
AccountCompletion(GameInstance, TEXT("Registration accepted")));
}
void ConfirmPlayerAccount(UGameInstance &GameInstance, const FString &Username, const FString &Code)
{
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
Accounts->ConfirmRegistration(
Username, Code,
AccountCompletion(GameInstance, TEXT("Account confirmed; sign in to continue")));
}
void ResendPlayerConfirmation(UGameInstance &GameInstance, const FString &Username)
{
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
Accounts->ResendConfirmation(
Username, AccountCompletion(GameInstance, TEXT("Confirmation code requested")));
}Use the same username for registration, confirmation, and resend. Add any other attributes your pool requires. These helpers report success/failure; they do not expose UserConfirmed or code-delivery details. Use the generated Cognito User Pools Sign Up node if your UI needs those fields. Neither confirmation nor registration establishes a game session.
Sign in
Sign in with SRP, then answer any MFA or password challenge. Only On Success means the player is signed in.
Loading the interactive viewer.
Game module dependencies: UCIKCore, BetideCore, Engine. Use this Game Instance class, or merge its members into your own.
// CognitoLoginGameInstance.h
#pragma once
#include "Engine/GameInstance.h"
#include "UCIKIdentitySubsystem.h"
#include "CognitoLoginGameInstance.generated.h"
UCLASS()
class UCognitoLoginGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
void SignInCognito(const FString &Username, const FString &Password);
UFUNCTION(BlueprintCallable)
void AnswerCognitoChallenge(const FString &Answer);
UFUNCTION(BlueprintCallable)
void CancelCognitoChallenge();
UPROPERTY(BlueprintReadOnly)
FUCIK_LoginUpdate CognitoLoginUpdate;
UPROPERTY(BlueprintReadOnly)
bool CognitoChallengePending = false;
};
// CognitoLoginGameInstance.cpp
#include "CognitoLoginGameInstance.h"
#include "UCIKCore.h"
void UCognitoLoginGameInstance::SignInCognito(const FString &Username, const FString &Password)
{
UUCIKIdentitySubsystem *Identity = GetSubsystem<UUCIKIdentitySubsystem>();
if (!Identity || Identity->IsLoginInProgress())
{
UE_LOG(LogUCIK, Warning, TEXT("Identity unavailable or a login is already in progress"));
return;
}
FUCIK_LoginRequest Request;
Request.LocalUserIndex = 0;
Request.MethodId = TEXT("Betide.Cognito.UserPool.SRP");
Request.Fields.FindOrAdd(TEXT("Username")).StringValue = Username;
Request.Fields.FindOrAdd(TEXT("Password")).StringValue = Password;
Identity->Login(
Request,
FUCIKLoginUpdateCallback::CreateWeakLambda(this, [this](const FUCIK_LoginUpdate &Update) {
CognitoLoginUpdate = Update;
CognitoChallengePending =
Update.Operation.State == EUCIK_LoginOperationState::NeedsChallengeResponse;
if (CognitoChallengePending)
{
UE_LOG(LogUCIK, Log, TEXT("%s"), *Update.Challenge.Prompt.ToString());
}
else if (Update.Operation.IsTerminal())
{
if (Update.Operation.State == EUCIK_LoginOperationState::Succeeded)
{
UE_LOG(LogUCIK, Log, TEXT("Signed in to Cognito"));
}
else
{
UE_LOG(LogUCIK, Warning, TEXT("%s"), *Update.Error.Message);
}
}
}));
}
void UCognitoLoginGameInstance::AnswerCognitoChallenge(const FString &Answer)
{
if (!CognitoChallengePending)
{
UE_LOG(LogUCIK, Warning, TEXT("No Cognito challenge is waiting for an answer"));
return;
}
UUCIKIdentitySubsystem *Identity = GetSubsystem<UUCIKIdentitySubsystem>();
if (!Identity)
{
return;
}
TMap<FName, FUCIK_LoginFieldValue> Responses;
Responses.FindOrAdd(CognitoLoginUpdate.Challenge.ResponseFields[0].FieldId).StringValue =
Answer;
CognitoChallengePending = false;
Identity->ContinueLogin(CognitoLoginUpdate.Operation, Responses);
}
void UCognitoLoginGameInstance::CancelCognitoChallenge()
{
if (!CognitoChallengePending)
{
UE_LOG(LogUCIK, Warning, TEXT("No Cognito challenge is waiting for an answer"));
return;
}
if (UUCIKIdentitySubsystem *Identity = GetSubsystem<UUCIKIdentitySubsystem>())
{
CognitoChallengePending = false;
Identity->CancelLogin(CognitoLoginUpdate.Operation);
}
}Required variables: CognitoLoginUpdate (Crossplay Login Update) and CognitoChallengePending (Boolean, false). Keep this flow in a Game Instance and route login requests through it.
Show CognitoLoginUpdate.Challenge.Prompt in your UI. This SRP flow returns one response field; Answer Cognito Challenge uses its ID automatically. Cancel Cognito Challenge cancels while that prompt is waiting. Neither event starts a new login. Do not log passwords or challenge answers.
Temporary AWS access
With an Identity Pool configured, User Pool login also exchanges the verified ID token for AWS credentials before reporting success. A failed exchange fails login, even if the password was correct. Check the pool’s trusted provider, app client, authenticated role, and role permissions.
Select Cognito Identity Pool as the AWS credential source. The plugin supplies and renews the temporary credentials; you do not copy access keys into project settings. Grant access only to the player’s intended resources.
Password recovery
Enable self-service account recovery in the pool. The player needs an eligible verified email address or phone number. AWS recovery requirements
Request a password reset code
Loading the interactive viewer.
Reset the player password
Loading the interactive viewer.
Change a signed-in player password
Loading the interactive viewer.
Uses AccountCompletion and the includes from Register and confirm. Call each function after collecting its input.
void RequestPasswordReset(UGameInstance &GameInstance, const FString &Username)
{
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
Accounts->BeginPasswordReset(
Username, AccountCompletion(GameInstance, TEXT("Password reset code requested")));
}
void ResetPlayerPassword(UGameInstance &GameInstance, const FString &Username, const FString &Code,
const FString &NewPassword)
{
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
Accounts->CompletePasswordReset(
Username, Code, NewPassword,
AccountCompletion(GameInstance, TEXT("Password reset; sign in with the new password")));
}
void ChangePlayerPassword(UGameInstance &GameInstance, const FString &PreviousPassword,
const FString &NewPassword)
{
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
Accounts->ChangePassword(0, PreviousPassword, NewPassword,
AccountCompletion(GameInstance, TEXT("Password changed")));
}Use the same username for both reset steps. Resetting a password does not sign the player in. Change Password requires a verified Cognito session for local user 0; after managed login, its access token needs aws.cognito.signin.user.admin. AWS change-password requirements
The reset helper does not return the code delivery destination. Use Cognito User Pools Forgot Password if your UI needs it. Keep password and code inputs out of logs.
Managed browser login
Set User Pool Domain, User Pool Redirect Uri, and the app client’s matching allowed callback URL. Enable the authorization-code grant and requested scopes.
Choose Cognito · Managed Login (Betide.Cognito.UserPool.ManagedLogin). The plugin opens the browser and uses PKCE. Your game must receive the redirect and pass its code and state back as AuthorizationCode and State through Continue Crossplay Login. The plugin does not install a callback URL handler for your game. Accept only your configured callback URL and pass its decoded query values unchanged; the plugin checks state before exchanging the code. Closing the browser does not cancel login—call Cancel Cognito Browser Login when the player cancels or the callback returns an OAuth error.
For account-management calls after browser login, also enable and request aws.cognito.signin.user.admin in Managed Login Scopes; the default openid and profile scopes are insufficient. AWS account scope
Loading the interactive viewer.
Game module dependencies: UCIKCore, BetideCore, Engine. Use this Game Instance class, or merge its members into your own.
// CognitoBrowserGameInstance.h
#pragma once
#include "Engine/GameInstance.h"
#include "UCIKIdentitySubsystem.h"
#include "CognitoBrowserGameInstance.generated.h"
UCLASS()
class UCognitoBrowserGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
void StartCognitoBrowserLogin();
UFUNCTION(BlueprintCallable)
void CompleteCognitoBrowserLogin(const FString &Code, const FString &ReturnedState);
UFUNCTION(BlueprintCallable)
void CancelCognitoBrowserLogin();
UPROPERTY(BlueprintReadOnly)
FUCIK_LoginUpdate CognitoBrowserUpdate;
UPROPERTY(BlueprintReadOnly)
bool CognitoBrowserPending = false;
};
// CognitoBrowserGameInstance.cpp
#include "CognitoBrowserGameInstance.h"
#include "UCIKCore.h"
void UCognitoBrowserGameInstance::StartCognitoBrowserLogin()
{
UUCIKIdentitySubsystem *Identity = GetSubsystem<UUCIKIdentitySubsystem>();
if (!Identity || Identity->IsLoginInProgress())
{
UE_LOG(LogUCIK, Warning, TEXT("Identity unavailable or a login is already in progress"));
return;
}
FUCIK_LoginRequest Request;
Request.LocalUserIndex = 0;
Request.MethodId = TEXT("Betide.Cognito.UserPool.ManagedLogin");
Identity->Login(
Request,
FUCIKLoginUpdateCallback::CreateWeakLambda(this, [this](const FUCIK_LoginUpdate &Update) {
CognitoBrowserUpdate = Update;
CognitoBrowserPending =
Update.Operation.State == EUCIK_LoginOperationState::NeedsUserInterface;
if (CognitoBrowserPending)
{
UE_LOG(LogUCIK, Log, TEXT("%s"), *Update.Challenge.Prompt.ToString());
}
else if (Update.Operation.IsTerminal())
{
if (Update.Operation.State == EUCIK_LoginOperationState::Succeeded)
{
UE_LOG(LogUCIK, Log, TEXT("Signed in to Cognito"));
}
else
{
UE_LOG(LogUCIK, Warning, TEXT("%s"), *Update.Error.Message);
}
}
}));
}
void UCognitoBrowserGameInstance::CompleteCognitoBrowserLogin(const FString &Code,
const FString &ReturnedState)
{
if (!CognitoBrowserPending)
{
UE_LOG(LogUCIK, Warning, TEXT("No Cognito browser login is waiting for a callback"));
return;
}
UUCIKIdentitySubsystem *Identity = GetSubsystem<UUCIKIdentitySubsystem>();
if (!Identity)
{
return;
}
TMap<FName, FUCIK_LoginFieldValue> Responses;
Responses.FindOrAdd(TEXT("AuthorizationCode")).StringValue = Code;
Responses.FindOrAdd(TEXT("State")).StringValue = ReturnedState;
CognitoBrowserPending = false;
Identity->ContinueLogin(CognitoBrowserUpdate.Operation, Responses);
}
void UCognitoBrowserGameInstance::CancelCognitoBrowserLogin()
{
if (!CognitoBrowserPending)
{
UE_LOG(LogUCIK, Warning, TEXT("No Cognito browser login is waiting for a callback"));
return;
}
if (UUCIKIdentitySubsystem *Identity = GetSubsystem<UUCIKIdentitySubsystem>())
{
CognitoBrowserPending = false;
Identity->CancelLogin(CognitoBrowserUpdate.Operation);
}
}Required variables: CognitoBrowserUpdate (Crossplay Login Update) and CognitoBrowserPending (Boolean, false). Keep the flow in a Game Instance so it survives travel. Do not log the callback URL or authorization code.
MFA, one-time passwords, and passkeys
Sign in to the User Pool first. Enable software-token MFA in the pool; managed-login access tokens need aws.cognito.signin.user.admin. Show MfaContinuation.Secret in your setup UI while MfaReady is true, then submit the player’s six-digit authenticator code. Never log or save the secret. AWS authenticator setup
Loading the interactive viewer.
Game Instance variables: MfaBusy and MfaReady (Boolean, false), MfaContinuation (UCIKAccountContinuation). Dismiss clears local setup data; it does not disable MFA.
Game module dependencies: AWSIKCognito, BetideCore, Engine. Bind the setup UI to MfaReady and MfaContinuation.Secret.
// CognitoMfaGameInstance.h
#pragma once
#include "Engine/GameInstance.h"
#include "Accounts/IUCIKAccountProvider.h"
#include "CognitoMfaGameInstance.generated.h"
UCLASS()
class UCognitoMfaGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
void EnrollAuthenticator();
UFUNCTION(BlueprintCallable)
void ConfirmAuthenticator(const FString &Code);
UFUNCTION(BlueprintCallable)
void DismissAuthenticatorSetup();
UPROPERTY(BlueprintReadOnly, Transient)
bool MfaBusy = false;
UPROPERTY(BlueprintReadOnly, Transient)
bool MfaReady = false;
UPROPERTY(BlueprintReadOnly, Transient)
FUCIKAccountContinuation MfaContinuation;
};// CognitoMfaGameInstance.cpp
#include "CognitoMfaGameInstance.h"
#include "AWSIKCognito.h"
void UCognitoMfaGameInstance::EnrollAuthenticator()
{
if (MfaBusy)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("An MFA request is already running"));
return;
}
MfaReady = false;
MfaContinuation = {};
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
MfaBusy = true;
Accounts->EnrolMFA(
0, FUCIKAccountContinuationCallback::CreateWeakLambda(
this, [this](const TBetideResult<FUCIKAccountContinuation> &Result) {
MfaBusy = false;
if (!Result.bOk)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("%s"), *Result.Error.Message);
return;
}
MfaContinuation = Result.GetValue();
MfaReady = true;
UE_LOG(LogAWSIKCognito, Log, TEXT("Authenticator setup key is ready"));
}));
}
void UCognitoMfaGameInstance::ConfirmAuthenticator(const FString &Code)
{
if (MfaBusy || !MfaReady)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("Wait for enrollment before confirming the code"));
return;
}
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
MfaBusy = true;
Accounts->ConfirmMFA(
0, Code, MfaContinuation,
FBetideCallbackVoid::CreateWeakLambda(this, [this](const TBetideResult<void> &Result) {
MfaBusy = false;
if (!Result.bOk)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("%s"), *Result.Error.Message);
return;
}
MfaReady = false;
MfaContinuation = {};
UE_LOG(LogAWSIKCognito, Log, TEXT("Authenticator MFA enabled"));
}));
}
void UCognitoMfaGameInstance::DismissAuthenticatorSetup()
{
if (MfaBusy)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("Wait for the current MFA request to finish"));
return;
}
MfaReady = false;
MfaContinuation = {};
}A failed confirmation keeps setup available for retry. This flow enrolls an already signed-in player; handle login-time MFA challenges through Sign in.
Disable MFA disables only software-token MFA for signed-in local user 0. Call it after the player confirms the change. It does not reset the registered authenticator or change SMS/email preferences. Managed-login sessions need aws.cognito.signin.user.admin. AWS MFA preferences
Loading the interactive viewer.
Uses AccountCompletion and the includes from Register and confirm.
void DisableAuthenticatorAfterConfirmation(UGameInstance &GameInstance)
{
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
Accounts->DisableMFA(0, AccountCompletion(GameInstance, TEXT("Authenticator MFA disabled")));
}Email OTP, SMS OTP, MFA selection, passkey, and custom-challenge methods are also listed by Get Crossplay Login Methods. Their availability still depends on your pool, app client, and AWS feature tier. Choice-based methods use USER_AUTH; custom challenges use CUSTOM_AUTH.
Passkey login expects a WebAuthn CREDENTIAL response from your own integration. Selecting that method alone does not open a native passkey picker. Handle the returned challenge fields rather than assuming every challenge is a six-digit code.
Profile, devices, and account deletion
These operations require a verified User Pool session. Attribute updates must be allowed by the app client. Device listing reflects Cognito’s remembered devices; it is not a list of every active game client.
Read the account profile
Loading the interactive viewer.
Update the player nickname
Loading the interactive viewer.
List remembered devices
Loading the interactive viewer.
Forget a selected device
Loading the interactive viewer.
Delete the confirmed account
Loading the interactive viewer.
Game module dependencies: AWSIKCognito, AWSIKCore, BetideCore, UCIKCore, Engine. Uses AccountCompletion from Register and confirm.
#include "Engine/GameInstance.h"
#include "AWSIKCognito.h"
#include "Accounts/IUCIKAccountProvider.h"
#include "Providers/AWSIKProviderIds.h"
#include "UCIKIdentitySubsystem.h"
void ReadAccountProfile(UGameInstance &GameInstance)
{
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
Accounts->GetProfile(
0, FUCIKAccountProfileCallback::CreateWeakLambda(
&GameInstance, [](const TBetideResult<FUCIKAccountProfile> &Result) {
if (!Result.bOk)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("%s"), *Result.Error.Message);
return;
}
const FUCIKAccountProfile &Profile = Result.GetValue();
UE_LOG(LogAWSIKCognito, Log, TEXT("%s: %d attributes"), *Profile.Username,
Profile.Attributes.Num());
}));
}
void UpdatePlayerNickname(UGameInstance &GameInstance, const FString &Nickname)
{
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
FUCIKAccountAttribute Attribute;
Attribute.Name = TEXT("nickname");
Attribute.Value = Nickname;
Accounts->UpdateProfile(0, {Attribute},
AccountCompletion(GameInstance, TEXT("Nickname updated")));
}
void ReadRememberedDevices(UGameInstance &GameInstance)
{
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
Accounts->ListDevices(
0, FUCIKAccountDevicesCallback::CreateWeakLambda(
&GameInstance, [](const TBetideResult<TArray<FUCIKAccountDevice>> &Result) {
if (!Result.bOk)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("%s"), *Result.Error.Message);
return;
}
for (const FUCIKAccountDevice &Device : Result.GetValue())
{
UE_LOG(LogAWSIKCognito, Log, TEXT("%s: last authenticated %s"), *Device.Id,
*Device.LastAuthenticatedAt.ToIso8601());
}
UE_LOG(LogAWSIKCognito, Log, TEXT("Device list loaded"));
}));
}
void ForgetSelectedDevice(UGameInstance &GameInstance, const FString &DeviceId)
{
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
Accounts->ForgetDevice(0, DeviceId, AccountCompletion(GameInstance, TEXT("Device forgotten")));
}
void DeletePlayerAccountAfterConfirmation(UGameInstance &GameInstance)
{
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
Accounts->DeleteAccount(
0, FBetideCallbackVoid::CreateWeakLambda(
&GameInstance, [&GameInstance](const TBetideResult<void> &Result) {
if (!Result.bOk)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("%s"), *Result.Error.Message);
return;
}
UE_LOG(LogAWSIKCognito, Log, TEXT("Cognito account deleted"));
UUCIKIdentitySubsystem *Identity =
GameInstance.GetSubsystem<UUCIKIdentitySubsystem>();
if (!Identity)
{
UE_LOG(LogAWSIKCognito, Warning,
TEXT("Identity subsystem unavailable for local cleanup"));
return;
}
Identity->Logout(
BetideProviderIds::CognitoUserPool, 0, EUCIK_LogoutScope::LocalCache,
FUCIKLogoutCallback::CreateWeakLambda(
&GameInstance, [](const TBetideResult<FUCIK_LogoutResult> &Logout) {
if (!Logout.bOk)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("%s"),
*Logout.Error.Message);
return;
}
UE_LOG(LogAWSIKCognito, Log, TEXT("Local sign-in state cleared"));
}));
}));
}Allow nickname writes in the app client. Email/phone updates can need verification; the update helper does not expose code-delivery details.
Pass a returned device Id to Forget Device. The helper lists pages automatically, up to 100 pages or 10,000 devices, then fails if more remain. It currently uses the device ID as its display name.
Delete only after the player confirms. The example deletes the Cognito account, then clears local crossplay sign-in state using Local Cache scope. It does not delete your game’s stored data or the browser’s login cookie.
Federation and account linking
Google and Apple Identity Pool routes exchange their ID tokens for AWS access. Configure those providers in the Identity Pool. They do not create a User Pool password account.
Cognito Identity Pool · Steam additionally needs a deployed exchange backend, Exchange Endpoint, and matching Steam Ticket Audience. Its short-lived bearer token comes from the environment variable named by Exchange Auth Environment Variable. Keep the Steam verification credentials on that backend.
The User Pool provider rejects client-side account merging with link_requires_project_backend. Configure federation or implement linking on a trusted backend; signing in twice does not merge progression.
Tokens and sign-out
The plugin keeps verified sessions in memory and refreshes them before expiry. Do not log passwords, tokens, or challenge answers. Your backend must verify a token before using its claims.
For a signed-in Cognito player, Logout From Crossplay with Authority Session + Local Cache calls global sign-out and clears local identity. This affects the user’s Cognito tokens across sessions. Managed login needs aws.cognito.signin.user.admin. AWS global sign-out
To revoke only the stored refresh-token session, use Revoke Session, then Logout From Crossplay → Local Cache. The app client must support token revocation, and the stored session must contain a refresh token. AWS token revocation
Sign out of Cognito
Loading the interactive viewer.
Revoke the current Cognito session
Loading the interactive viewer.
Game module dependencies: AWSIKCognito, AWSIKCore, BetideCore, UCIKCore, Engine.
#include "Engine/GameInstance.h"
#include "AWSIKCognito.h"
#include "Accounts/IUCIKAccountProvider.h"
#include "Providers/AWSIKProviderIds.h"
#include "UCIKIdentitySubsystem.h"
void SignOutCognito(UGameInstance &GameInstance)
{
UUCIKIdentitySubsystem *Identity = GameInstance.GetSubsystem<UUCIKIdentitySubsystem>();
if (!Identity)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The identity subsystem is unavailable"));
return;
}
Identity->Logout(BetideProviderIds::CognitoUserPool, 0,
EUCIK_LogoutScope::AuthoritySession | EUCIK_LogoutScope::LocalCache,
FUCIKLogoutCallback::CreateWeakLambda(
&GameInstance, [](const TBetideResult<FUCIK_LogoutResult> &Result) {
if (!Result.bOk)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("%s"),
*Result.Error.Message);
return;
}
UE_LOG(LogAWSIKCognito, Log, TEXT("Signed out of Cognito"));
}));
}
void RevokeCurrentCognitoSession(UGameInstance &GameInstance)
{
const auto Accounts = FAWSIKCognitoModule::Get().GetAccountProvider();
if (!Accounts)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("The Cognito account provider is unavailable"));
return;
}
Accounts->RevokeSession(
0, FBetideCallbackVoid::CreateWeakLambda(
&GameInstance, [&GameInstance](const TBetideResult<void> &Result) {
if (!Result.bOk)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("%s"), *Result.Error.Message);
return;
}
UE_LOG(LogAWSIKCognito, Log, TEXT("Cognito session revoked"));
UUCIKIdentitySubsystem *Identity =
GameInstance.GetSubsystem<UUCIKIdentitySubsystem>();
if (!Identity)
{
UE_LOG(LogAWSIKCognito, Warning,
TEXT("Identity subsystem unavailable for local cleanup"));
return;
}
Identity->Logout(
BetideProviderIds::CognitoUserPool, 0, EUCIK_LogoutScope::LocalCache,
FUCIKLogoutCallback::CreateWeakLambda(
&GameInstance, [](const TBetideResult<FUCIK_LogoutResult> &Logout) {
if (!Logout.bOk)
{
UE_LOG(LogAWSIKCognito, Warning, TEXT("%s"),
*Logout.Error.Message);
return;
}
UE_LOG(LogAWSIKCognito, Log, TEXT("Local sign-in state cleared"));
}));
}));
}Neither flow clears the managed-login browser cookie. To sign out that browser too, open your domain’s Cognito logout endpoint with client_id and an encoded logout_uri matching an allowed sign-out URL. Offline JWT validation can still accept a revoked token until expiry; enforce revocation in your backend if immediate denial is required. Revocation limits