Skip to main content

Authentication using the Unreal Engine SDK

Last updated on December 18, 2024

Overview

AGS Shared Cloud

This topic is specific to the AccelByte Gaming Services (AGS) Shared Cloud tier.

The Authentication service is part of the AccelByte services that provides multilayer security via the OAuth 2.0 specification. This is described in detail in the Access service section.

Prerequisites

The examples in this document use the latest version of AGS Shared Cloud's UE SDK and AGS Shared Cloud's UE OSS.

note

Other versions may need different steps to implement. See AGS OSS for Unreal Engine for more information on setting up the OSS.

Quick reference

References

#include "OnlineIdentityInterfaceAccelByte.h"
#include "OnlineSubsystemUtils.h"

Login

IdentityInterface->AddOnLoginCompleteDelegate_Handle(USER_LOCAL_NUM, 
FOnLoginCompleteDelegate::CreateLambda([this, IdentityInterface]
(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error)
{
IdentityInterface->ClearOnLoginCompleteDelegate_Handle(USER_LOCAL_NUM, OnLoginCompleteDelegateHandle);

if (bWasSuccessful)
{
LoginSuccess();
}
else
{
LoginFailed(Error);
}
}));

const FOnlineAccountCredentialsAccelByte OnlineAccountCredentialsAccelByte
{EAccelByteLoginType::AccelByte, "Username", "Password"};

IdentityInterface->Login(USER_LOCAL_NUM, OnlineAccountCredentialsAccelByte);

Logout

IdentityInterface->AddOnLogoutCompleteDelegate_Handle(USER_LOCAL_NUM, 
FOnLogoutCompleteDelegate::CreateLambda([this, IdentityInterface](int32 LocalUserNum, bool bWasSuccessful)
{
IdentityInterface->ClearOnLogoutCompleteDelegate_Handle(USER_LOCAL_NUM, OnLogoutCompleteDelegateHandle);

if (bWasSuccessful)
{
LogoutSuccess();
}
else
{
LogoutFailed();
}
}));

IdentityInterface->Logout(USER_LOCAL_NUM);

Quickstart

In this section, you will learn how to enable authentication using AccelByte Gaming Services (AGS) Shared Cloud's IAM services.

  1. Create a user widget C++ class named AccelByteAuth which will specify the authentication flow between functions when creating an authentication system.

  2. Add the AccelByte header to ensure the functions will work correctly for the IAM services.

    .cpp

    ...
    #include "OnlineIdentityInterfaceAccelByte.h"
    #include "OnlineSubsystemUtils.h"
    ...
  3. Use the LoginWithUsername() function to create a new function to handle logins when players use their username or email.

    .cpp

    void UAccelByteAuth::OnLoginButtonClicked()
    {
    T_LoginStatus->SetText(FText::FromString("Logging in..."));

    const IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());
    ensure(Subsystem != nullptr);

    const FOnlineIdentityAccelBytePtr IdentityInterface = StaticCastSharedPtr<FOnlineIdentityAccelByte>(Subsystem->GetIdentityInterface());
    ensure(IdentityInterface.IsValid());

    OnLoginCompleteDelegateHandle = IdentityInterface->AddOnLoginCompleteDelegate_Handle(
    USER_LOCAL_NUM, FOnLoginCompleteDelegate::CreateLambda([this, IdentityInterface]
    (int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error)
    {
    IdentityInterface->ClearOnLoginCompleteDelegate_Handle(USER_LOCAL_NUM, OnLoginCompleteDelegateHandle);

    if (bWasSuccessful)
    {
    LoginSuccess();
    }
    else
    {
    LoginFailed(Error);
    }
    }));

    const FString& Username = Etb_Username->GetText().ToString();
    const FString& Password = Etb_Password->GetText().ToString();
    const FOnlineAccountCredentialsAccelByte OnlineAccountCredentialsAccelByte
    {EAccelByteLoginType::AccelByte, Username, Password};

    IdentityInterface->Login(USER_LOCAL_NUM, OnlineAccountCredentialsAccelByte);
    }

    .h

    ...
    /**
    * @brief Log an account in using the AccelByte SDK. This is executed automatically on component construction unless
    * otherwise configured.
    */
    UFUNCTION()
    void OnLoginButtonClicked();
    ...
  4. Create another new function to handle the logout flow using the Logout() function.

    .cpp

    void UAccelByteAuth::OnLogoutButtonClicked()
    {
    const IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());
    ensure(Subsystem != nullptr);

    const FOnlineIdentityAccelBytePtr IdentityInterface = StaticCastSharedPtr<FOnlineIdentityAccelByte>(Subsystem->GetIdentityInterface());
    ensure(IdentityInterface.IsValid());

    OnLogoutCompleteDelegateHandle = IdentityInterface->AddOnLogoutCompleteDelegate_Handle(
    USER_LOCAL_NUM, FOnLogoutCompleteDelegate::CreateLambda([this, IdentityInterface](int32 LocalUserNum, bool bWasSuccessful)
    {
    IdentityInterface->ClearOnLogoutCompleteDelegate_Handle(USER_LOCAL_NUM, OnLogoutCompleteDelegateHandle);

    if (bWasSuccessful)
    {
    LogoutSuccess();
    }
    else
    {
    LogoutFailed();
    }
    }));

    IdentityInterface->Logout(USER_LOCAL_NUM);
    }

    .h

    ...
    /**
    * @brief Log out a session using the AccelByte SDK. This is executed automatically on component construction unless
    * otherwise configured.
    */
    UFUNCTION()
    void OnLogoutButtonClicked();
    ...
  5. Test your login flow by calling it from any of the other classes or functions that will be loaded first. In this case, you will use the NativeConstruct() function which manages the construction of widgets at the very beginning. You can specify some sample credentials for Username and Password for testing purposes.

    .cpp

    void UAccelByteAuth::NativeConstruct()
    {
    Super::NativeConstruct();

    Btn_Login->OnClicked.AddUniqueDynamic(this, &UAccelByteAuth::OnLoginButtonClicked);
    }

    .h

    ...
    virtual void NativeConstruct() override;
    ...
    TIP:

    If you get a Login failed message, check your login credentials and the API URLs supplied in the DefaultEngine.ini file. If the error is related to .JSON reading, check the format of your DefaultEngine.ini file.

    Log in to the AGS Shared Cloud Admin Portal to set up your game backend online features.

UsernamePassword
tutorial+demo1@accelbyte.netPassword123
tutorial+demo2@accelbyte.netPassword123
tutorial+demo3@accelbyte.netPassword123
tutorial+demo4@accelbyte.netPassword123
tutorial+demo5@accelbyte.netPassword123
tutorial+demo6@accelbyte.netPassword123

Congratulations! You have successfully learned how to implement Authentication.

Continue on for a step-by-step example of the associated widget and code implementation. Otherwise, you are now ready to move on to the Lobby.

Step-by-step guide

danger

The logout screen menu is not included in this guide. To log out, use the logout function.

Implement the UI

  1. Create a widget blueprint class named WB_LoginMenu and re-parent the WB_LoginMenu widget blueprint to the AccelByteAuth C++ class.

  2. Create a Login Page with the following object components:

    • Editable text box for username input
    • Editable text box for password input
    • Button for the login action
    • Text block for the login status text.

Implement the code

  1. Include the widget-related classes at the top of the class for widget implementation.

    ...
    #include "Components/Button.h"
    #include "Components/EditableTextBox.h"
    #include "Components/TextBlock.h"
  2. Specify all the widget components in the AccelByteAuth header file.

    .h

    ...

    UPROPERTY(meta = (BindWidget))
    UEditableTextBox* Etb_Username;

    UPROPERTY(meta = (BindWidget))
    UEditableTextBox* Etb_Password;

    UPROPERTY(meta = (BindWidget))
    UButton* Btn_Login;

    UPROPERTY(meta = (BindWidget))
    UTextBlock* T_LoginStatus;
    ...
  3. Remove the OnLoginButtonClicked() call in the NativeConstruct() function. Then, set the Login's Canvas Panel to be visible and bind the Login button to its function.

    .cpp

    void UAccelByteAuth::NativeConstruct()
    {
    Super::NativeConstruct();

    UE_LOG(LogTemp, Log, TEXT("Login with Username"));

    T_LoginStatus->SetText(FText::FromString("Please Login"));
    Btn_Login->OnClicked.AddUniqueDynamic(this, &UAccelByteAuth::OnLoginButtonClicked);
    }
  4. In OnLoginButtonClicked(), delete the function's parameters and update the function to retrieve credentials from widgets instead.

  5. To make it easier to differentiate the responses, create two new functions and then create two UObject delegate functions to subscribe to the delegate if the response succeeds or fails.

    .cpp

    void UAccelByteAuth::OnLoginButtonClicked()
    {
    T_LoginStatus->SetText(FText::FromString("Logging in..."));

    const IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());
    ensure(Subsystem != nullptr);

    const FOnlineIdentityAccelBytePtr IdentityInterface = StaticCastSharedPtr<FOnlineIdentityAccelByte>(Subsystem->GetIdentityInterface());
    ensure(IdentityInterface.IsValid());

    OnLoginCompleteDelegateHandle = IdentityInterface->AddOnLoginCompleteDelegate_Handle(USER_LOCAL_NUM, FOnLoginCompleteDelegate::CreateLambda([this, IdentityInterface]
    (int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error)
    {
    IdentityInterface->ClearOnLoginCompleteDelegate_Handle(USER_LOCAL_NUM, OnLoginCompleteDelegateHandle);

    if (bWasSuccessful)
    {
    LoginSuccess();
    }
    else
    {
    LoginFailed(Error);
    }
    }));

    const FString& Username = Etb_Username->GetText().ToString();
    const FString& Password = Etb_Password->GetText().ToString();
    const FOnlineAccountCredentialsAccelByte OnlineAccountCredentialsAccelByte
    {EAccelByteLoginType::AccelByte, Username, Password};

    IdentityInterface->Login(USER_LOCAL_NUM, OnlineAccountCredentialsAccelByte);
    }
  6. Both of the UObject delegate functions can be used to call other functions after a successful or failed login. Set the text for the Login Status to inform the user about where they are in the process.

    ...
    void UAccelByteAuth::LoginSuccess()
    {
    UE_LOG(LogTemp, Log, TEXT("Login Success"));
    T_LoginStatus->SetText(FText::FromString("Login successful"));
    }

    void UAccelByteAuth::LoginFailed(const FString& ErrorMessage)
    {
    UE_LOG(LogTemp, Error, TEXT("Login Failed : %s"), *ErrorMessage);
    T_LoginStatus->SetText(FText::FromString(FString::Printf(TEXT("Login Failed : %s"), *ErrorMessage)));
    }
    ...
  7. In OnLogoutButtonClicked(), modify the logout function's parameter to call UObject delegate functions to subscribe to the delegate if the response succeeds or fails.

    .cpp

    void UAccelByteAuth::OnLogoutButtonClicked()
    {
    const IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());
    ensure(Subsystem != nullptr);

    const FOnlineIdentityAccelBytePtr IdentityInterface = StaticCastSharedPtr<FOnlineIdentityAccelByte>(Subsystem->GetIdentityInterface());
    ensure(IdentityInterface.IsValid());

    OnLogoutCompleteDelegateHandle = IdentityInterface->AddOnLogoutCompleteDelegate_Handle(
    USER_LOCAL_NUM, FOnLogoutCompleteDelegate::CreateLambda([this, IdentityInterface](int32 LocalUserNum, bool bWasSuccessful)
    {
    IdentityInterface->ClearOnLogoutCompleteDelegate_Handle(USER_LOCAL_NUM, OnLogoutCompleteDelegateHandle);

    if (bWasSuccessful)
    {
    LogoutSuccess();
    }
    else
    {
    LogoutFailed();
    }
    }));

    IdentityInterface->Logout(USER_LOCAL_NUM);
    }
  8. Both of the UObject delegate functions can be used to call other functions after a successful or failed logout. For now, add a log to inform the user of the Logout query response.

    ...
    void UAccelByteAuth::LogoutSuccess()
    {
    UE_LOG(LogTemp, Log, TEXT("Logout Success"));
    }

    void UAccelByteAuth::LogoutFailed()
    {
    UE_LOG(LogTemp, Error, TEXT("Logout Failed"));
    }
    ...
  9. Save the class, build the project, press Play, and type in your credentials.

    The results of the process will be displayed in the Login Status box. If your credentials are incorrect, an error message will appear in the status box.

Congratulations! You have now fully implemented Logins, which are the gateway to all of AGS.

Full code for reference

AccelByteAuth.h
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "AccelByteAuth.generated.h"

class UVerticalBox;
class UEditableTextBox;
class UButton;
class ATutorialMenuHUD;
class UTextBlock;

/**
* Component for logging in a user with the AccelByte backend as well as methods for grabbing information relating to that user.
* This code covers AccelByte services including :
*
* - Login with username
*/

UCLASS()
class TUTORIALPROJECT_API UAccelByteAuth : public UUserWidget
{
GENERATED_BODY()

protected:

virtual void NativeConstruct() override;

/**
* @brief Editable Text Box for Username inside MainMenu Widget.
*/
UPROPERTY(meta = (BindWidget))
UEditableTextBox* Etb_Username;

/**
* @brief Editable Text Box for Password inside MainMenu Widget.
*/
UPROPERTY(meta = (BindWidget))
UEditableTextBox* Etb_Password;

/**
* @brief Take Button Login inside MainMenu Widget.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Login;

/**
* @brief Text Block to display Login Status
*/
UPROPERTY(meta = (BindWidget))
UTextBlock* T_LoginStatus;

/**
* @brief Instantiate all casting to the main menu HUD
*/
UPROPERTY()
ATutorialMenuHUD* TutorialMenuHUD;

/**
* @brief Delegate on login complete
*/
FDelegateHandle OnLoginCompleteDelegateHandle;

/**
* @brief Delegate on logout complete
*/
FDelegateHandle OnLogoutCompleteDelegateHandle;

public:

/**
* @brief Log in an account using the AccelByte SDK. This is executed automatically on component construction unless
* otherwise configured.
*/
UFUNCTION()
void OnLoginButtonClicked();

/**
* @brief Logo ut a session using the AccelByte SDK. This is executed automatically on component construction unless
* otherwise configured.
*/
UFUNCTION()
void OnLogoutButtonClicked();

private:

/**
* @brief Function behavior when login is successful. This function, which is called from inside AccelByte Login OnSuccess,
* delegates inside lambda. How the login behavior works inside this function can be changed.
*/
void LoginSuccess();

/**
* @brief Function behavior when login fails. This function, which is called from inside AccelByte Login OnFailed,
* delegates inside lambda. How the login behavior works inside this function can be changed.
*
* @param ErrorMessage error message HTTP request. e.g Unauthorized.
*/
void LoginFailed(const FString& ErrorMessage);

/**
* @brief Function behavior when logout is successful. This function, which is called from inside AccelByte Logout OnSuccess,
* delegates inside lambda. How the login behavior works inside this function can be changed.
*/
void LogoutSuccess();

/**
* @brief Function behavior when logout fails. This function, which is called from inside AccelByte Logout OnFailed,
* delegates inside lambda. How the login behavior works inside this function can be changed.
*/
void LogoutFailed();
};
AccelByteAuth.cpp
// Copyright (c) 2021 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.

#include "AccelByteAuth.h"

#include "OnlineIdentityInterfaceAccelByte.h"
#include "OnlineSubsystemUtils.h"
#include "Components/Button.h"
#include "Components/EditableTextBox.h"
#include "Components/TextBlock.h"

#define USER_LOCAL_NUM 0

void UAccelByteAuth::NativeConstruct()
{
Super::NativeConstruct();

UE_LOG(LogTemp, Log, TEXT("Login with Username"));

T_LoginStatus->SetText(FText::FromString("Please Login"));
Btn_Login->OnClicked.AddUniqueDynamic(this, &UAccelByteAuth::OnLoginButtonClicked);
}

void UAccelByteAuth::OnLoginButtonClicked()
{
T_LoginStatus->SetText(FText::FromString("Logging in..."));

const IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());
ensure(Subsystem != nullptr);

const FOnlineIdentityAccelBytePtr IdentityInterface = StaticCastSharedPtr<FOnlineIdentityAccelByte>(Subsystem->GetIdentityInterface());
ensure(IdentityInterface.IsValid());

OnLoginCompleteDelegateHandle = IdentityInterface->AddOnLoginCompleteDelegate_Handle(USER_LOCAL_NUM, FOnLoginCompleteDelegate::CreateLambda([this, IdentityInterface]
(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error)
{
IdentityInterface->ClearOnLoginCompleteDelegate_Handle(USER_LOCAL_NUM, OnLoginCompleteDelegateHandle);

if (bWasSuccessful)
{
LoginSuccess();
}
else
{
LoginFailed(Error);
}
}));

const FString& Username = Etb_Username->GetText().ToString();
const FString& Password = Etb_Password->GetText().ToString();
const FOnlineAccountCredentialsAccelByte OnlineAccountCredentialsAccelByte
{EAccelByteLoginType::AccelByte, Username, Password};

IdentityInterface->Login(USER_LOCAL_NUM, OnlineAccountCredentialsAccelByte);
}

void UAccelByteAuth::OnLogoutButtonClicked()
{
const IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());
ensure(Subsystem != nullptr);

const FOnlineIdentityAccelBytePtr IdentityInterface = StaticCastSharedPtr<FOnlineIdentityAccelByte>(Subsystem->GetIdentityInterface());
ensure(IdentityInterface.IsValid());

OnLogoutCompleteDelegateHandle = IdentityInterface->AddOnLogoutCompleteDelegate_Handle(USER_LOCAL_NUM, FOnLogoutCompleteDelegate::CreateLambda([this, IdentityInterface](int32 LocalUserNum, bool bWasSuccessful)
{
IdentityInterface->ClearOnLogoutCompleteDelegate_Handle(USER_LOCAL_NUM, OnLogoutCompleteDelegateHandle);

if (bWasSuccessful)
{
LogoutSuccess();
}
else
{
LogoutFailed();
}
}));

IdentityInterface->Logout(USER_LOCAL_NUM);
}

void UAccelByteAuth::LoginSuccess()
{
UE_LOG(LogTemp, Log, TEXT("Login Success"));
T_LoginStatus->SetText(FText::FromString("Login successful"));
}

void UAccelByteAuth::LoginFailed(const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Login Failed : %s"), *ErrorMessage);
T_LoginStatus->SetText(FText::FromString(FString::Printf(TEXT("Login Failed : %s"), *ErrorMessage)));
}

void UAccelByteAuth::LogoutSuccess()
{
UE_LOG(LogTemp, Log, TEXT("Logout Success"));
}

void UAccelByteAuth::LogoutFailed()
{
UE_LOG(LogTemp, Error, TEXT("Logout Failed"));
}