Full guide to authenticating players through Epic Online Services (EOS) and bridging their identity into Supabase for database access control. Covers the low-level USupabaseEOSIntegration API, the UAsyncLoginEOS convenience node, and step-by-step Blueprint setup.
EOS authentication lets players sign in through the Epic Games Launcher or EOS Connect, with their identity seamlessly passed to Supabase. The plugin provides two approaches:
| Approach | Class | Complexity | Best For |
|---|---|---|---|
| Convenience Node | UAsyncLoginEOS |
Low | Most use cases. Handles the full flow automatically. |
| Low-Level API | USupabaseEOSIntegration |
Medium | Custom flows where you need fine-grained control over each step. |
Both approaches ultimately produce the same result: a Supabase session linked to the player's EOS identity, enabling Row Level Security and database queries on behalf of that player.
The complete authentication pipeline from game startup to an active Supabase session:
+----------------+ +----------------+ +-----------------+
| Initialize() | ----> | Authenticate() | ----> | OnAuthComplete |
| EOS SDK | | ClientId + | | Delegate fires |
| Platform | | ClientSecret | | |
+----------------+ +----------------+ +-------+---------+
|
v
+----------------+ +----------------+ +-----------------+
| Supabase | <---- | GetExchange | <---- | FEOSAuthResult |
| Session Active | | Code() | | (success) |
| | | | | |
+----------------+ +----------------+ +-----------------+
--- Or using UAsyncLoginEOS (single call): ---
+----------------+ +----------------+ +-----------------+
| LoginWithEOS() | ----> | Internal flow | ----> | OnSuccess |
| (static call) | | handles all | | FEOSAuthResult |
| | | steps above | | |
+----------------+ +----------------+ +-----------------+
| Step | Action | Description |
|---|---|---|
| 1 | Initialize() |
Initializes the EOS SDK and platform services. Must be called before any other EOS operations. |
| 2 | Authenticate() |
Authenticates the player using your EOS Client ID and Client Secret. Triggers the OnAuthComplete delegate when finished. |
| 3 | OnAuthComplete |
Delegate fires with an FEOSAuthResult containing the authentication outcome. Check bWasSuccessful before proceeding. |
| 4 | GetExchangeCode() |
Retrieves the EOS exchange code from the authenticated session. This code is used to obtain a Supabase JWT. |
| 5 | Supabase Login | The exchange code is sent to Supabase to create or resume a user session. The player is now authenticated with both EOS and Supabase. |
For most projects, use the UAsyncLoginEOS async node. It handles the entire flow (EOS init, auth, exchange code retrieval, Supabase login) in a single Blueprint-compatible call.
Self #include "Async/AsyncLoginEOS.h"
UAsyncLoginEOS::LoginWithEOS(this)->OnSuccess.AddUObject(
this, &AMyPlayerController::OnEOSLoginSuccess);
// Handle the result
void AMyPlayerController::OnEOSLoginSuccess(const FEOSAuthResult& Result)
{
UE_LOG(LogTemp, Log, TEXT("Player: %s (PUID: %s)"),
*Result.DisplayName, *Result.ProductUserId);
// Supabase session is now active — you can make database calls
}
Use USupabaseEOSIntegration when you need direct control over each authentication step, or when building custom auth flows (e.g., showing your own loading UI between steps).
Call Initialize() once when your game starts (e.g., in BeginPlay or a startup subsystem). Call Shutdown() during cleanup.
#include "SupabaseEOSIntegration.h"
USupabaseEOSIntegration* EOSIntegration = NewObject<USupabaseEOSIntegration>(this);
// Initialize the EOS SDK
if (!EOSIntegration->Initialize())
{
UE_LOG(LogTemp, Error, TEXT("Failed to initialize EOS SDK"));
return;
}
UE_LOG(LogTemp, Log, TEXT("EOS SDK initialized successfully"));
After initialization, authenticate the player with their EOS credentials:
// Bind the auth complete delegate
EOSIntegration->OnAuthComplete.AddLambda(
[](const FEOSAuthResult& Result)
{
if (Result.bWasSuccessful)
{
UE_LOG(LogTemp, Log, TEXT("EOS auth succeeded. PUID: %s"),
*Result.ProductUserId);
}
else
{
UE_LOG(LogTemp, Error, TEXT("EOS auth failed: %s"),
*Result.ErrorMessage);
}
});
// Start authentication
const FString ClientId = TEXT("your-eos-client-id");
const FString ClientSecret = TEXT("your-eos-client-secret");
if (!EOSIntegration->Authenticate(ClientId, ClientSecret))
{
UE_LOG(LogTemp, Error, TEXT("Failed to start EOS authentication"));
}
Once authentication succeeds, retrieve the exchange code to pass to Supabase:
if (EOSIntegration->IsInitialized())
{
if (EOSIntegration->GetExchangeCode())
{
UE_LOG(LogTemp, Log, TEXT("Exchange code retrieved successfully"));
// The exchange code is available in the FEOSAuthResult from OnAuthComplete
}
}
Note: The exchange code is typically consumed automatically when using
UAsyncLoginEOS. When using the low-level API, you are responsible for passing the exchange code to Supabase's sign-in-with-provider endpoint.
| Function | Signature | Returns | Description |
|---|---|---|---|
Initialize |
bool Initialize() |
bool |
Initializes the EOS SDK and platform services. Returns true on success. Must be called before any other EOS operations. |
Shutdown |
void Shutdown() |
void |
Shuts down the EOS SDK and releases resources. Call during cleanup. |
IsInitialized |
bool IsInitialized() |
bool |
Returns true if the EOS SDK is currently initialized and ready for operations. |
Authenticate |
bool Authenticate(const FString& ClientId, const FString& ClientSecret) |
bool |
Begins EOS authentication with the provided credentials. Returns true if the auth request was started successfully. Results are delivered via the OnAuthComplete delegate. |
GetExchangeCode |
bool GetExchangeCode() |
bool |
Retrieves the EOS exchange code after successful authentication. Returns true if the code was retrieved successfully. |
| Delegate | Signature | Description |
|---|---|---|
OnAuthComplete |
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(OnAuthComplete, FEOSAuthResult, Result) |
Fired when the authentication flow completes (success or failure). The FEOSAuthResult parameter contains the outcome. |
A struct returned by EOS authentication operations. Contains the full result of the auth flow.
| Property | Type | Description |
|---|---|---|
bWasSuccessful |
bool |
true if authentication completed successfully; false otherwise. Always check this before using other fields. |
ExchangeCode |
FString |
The EOS exchange code. Used to authenticate with Supabase via the EOS auth provider. Empty on failure. |
ProductUserId |
FString |
The EOS Product User ID of the authenticated player. Unique identifier within your EOS product. Empty on failure. |
DisplayName |
FString |
The display name of the authenticated player from their EOS profile. Empty on failure. |
ErrorMessage |
FString |
Human-readable error description if authentication failed. Empty on success. |
A Blueprint-compatible async action node that handles the complete EOS-to-Supabase authentication flow in a single call.
| Method | Signature | Description |
|---|---|---|
LoginWithEOS |
static UAsyncLoginEOS* LoginWithEOS(UObject* WorldContextObject) |
Starts the full authentication flow. Call this from Blueprint or C++. Returns the async task object for delegate binding. |
| Delegate | Signature | Description |
|---|---|---|
OnSuccess |
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(OnSuccess, FEOSAuthResult, Result) |
Fired when the full flow completes successfully. The FEOSAuthResult contains the player's identity and a valid Supabase session is active. |
OnFailure |
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(OnFailure, FEOSAuthResult, Result) |
Fired when any step in the flow fails. Check Result.ErrorMessage for details. |
Supabase > Authentication > EOS
This example demonstrates using USupabaseEOSIntegration directly with full control over each step:
#include "SupabaseEOSIntegration.h"
void AMyPlayerController::BeginPlay()
{
Super::BeginPlay();
#if WITH_EOS_SDK && SUPABASE_EOS_INTEGRATION
// Create and initialize the EOS integration
EOSIntegration = NewObject<USupabaseEOSIntegration>(this);
if (!EOSIntegration->Initialize())
{
UE_LOG(LogTemp, Error, TEXT("EOS SDK initialization failed"));
ShowErrorMessage(TEXT("Failed to initialize EOS services."));
return;
}
// Bind the auth complete delegate
EOSIntegration->OnAuthComplete.AddUObject(
this, &AMyPlayerController::HandleEOSAuthComplete);
// Start authentication with EOS credentials
const FString ClientId = TEXT("your-eos-client-id");
const FString ClientSecret = TEXT("your-eos-client-secret");
if (!EOSIntegration->Authenticate(ClientId, ClientSecret))
{
UE_LOG(LogTemp, Error, TEXT("Failed to initiate EOS authentication"));
ShowErrorMessage(TEXT("Could not start authentication."));
return;
}
UE_LOG(LogTemp, Log, TEXT("EOS authentication initiated..."));
#else
UE_LOG(LogTemp, Warning,
TEXT("EOS integration not available. Using fallback auth."));
// Fall back to email/password or anonymous Supabase auth
#endif
}
void AMyPlayerController::HandleEOSAuthComplete(const FEOSAuthResult& Result)
{
if (!Result.bWasSuccessful)
{
UE_LOG(LogTemp, Error, TEXT("EOS auth failed: %s"), *Result.ErrorMessage);
ShowErrorMessage(Result.ErrorMessage);
return;
}
UE_LOG(LogTemp, Log, TEXT("EOS auth succeeded for: %s (PUID: %s)"),
*Result.DisplayName, *Result.ProductUserId);
// Retrieve the exchange code for Supabase
if (EOSIntegration->IsInitialized() && EOSIntegration->GetExchangeCode())
{
UE_LOG(LogTemp, Log, TEXT("Exchange code: %s"), *Result.ExchangeCode);
// Use the exchange code to sign in with Supabase
// (The UAsyncLoginEOS node handles this automatically;
// when using the low-level API, pass the exchange code
// to your Supabase sign-in-with-provider endpoint)
SignInWithSupabase(Result.ExchangeCode);
}
}
This example uses the UAsyncLoginEOS convenience node for a simpler integration:
#include "Async/AsyncLoginEOS.h"
void AMyGameMode::StartGameAuthentication()
{
#if WITH_EOS_SDK && SUPABASE_EOS_INTEGRATION
// One call handles: EOS init -> Auth -> ExchangeCode -> Supabase Login
UAsyncLoginEOS* LoginTask = UAsyncLoginEOS::LoginWithEOS(this);
if (!LoginTask)
{
UE_LOG(LogTemp, Error, TEXT("Failed to create LoginWithEOS task"));
return;
}
// Bind success handler
LoginTask->OnSuccess.AddUObject(
this, &AMyGameMode::OnLoginSuccess);
// Bind failure handler
LoginTask->OnFailure.AddUObject(
this, &AMyGameMode::OnLoginFailure);
#else
UE_LOG(LogTemp, Warning,
TEXT("EOS integration not available in this build."));
#endif
}
void AMyGameMode::OnLoginSuccess(const FEOSAuthResult& Result)
{
UE_LOG(LogTemp, Log, TEXT("Player authenticated: %s"), *Result.DisplayName);
UE_LOG(LogTemp, Log, TEXT("Product User ID: %s"), *Result.ProductUserId);
// Supabase session is now active — safe to make database calls
LoadPlayerData();
ShowMainMenu();
}
void AMyGameMode::OnLoginFailure(const FEOSAuthResult& Result)
{
UE_LOG(LogTemp, Error, TEXT("Login failed: %s"), *Result.ErrorMessage);
ShowErrorScreen(Result.ErrorMessage);
}
Follow the EOS Overview setup guide to enable EOS in your project. Ensure:
bEnableEOSIntegration = true in your Build.csSupabaseEOS module is listed in dependenciesOnlineSubsystemEOS is enabled in your .uprojectDefaultEngine.ini has the EOS configuration sectionsSelf or any valid world contextFEOSAuthResult output, pull DisplayName, ProductUserId, and ExchangeCodeErrorMessage from the FEOSAuthResult outputFor finer control, use the USupabaseEOSIntegration functions directly in Blueprint:
USupabaseEOSIntegration object (via Construct Object node)bWasSuccessful on the FEOSAuthResult| Node | Category | Description |
|---|---|---|
Login With EOS |
Supabase > Authentication > EOS | All-in-one async node. Handles init, auth, exchange code, and Supabase login. |
Initialize (USupabaseEOSIntegration) |
Supabase > EOS | Initializes the EOS SDK. Returns boolean. |
Shutdown (USupabaseEOSIntegration) |
Supabase > EOS | Shuts down the EOS SDK. |
Is Initialized (USupabaseEOSIntegration) |
Supabase > EOS | Check if EOS SDK is initialized. |
Authenticate (USupabaseEOSIntegration) |
Supabase > EOS | Begin EOS authentication with Client ID and Secret. |
Get Exchange Code (USupabaseEOSIntegration) |
Supabase > EOS | Retrieve the EOS exchange code after auth. |
| Error | Cause | Solution |
|---|---|---|
Initialize() returns false |
EOS SDK not available, missing dependencies, or already initialized | Verify OnlineSubsystemEOS plugin is enabled and the EOS SDK is installed. Ensure you are not calling Initialize() twice. |
Authenticate() returns false |
Invalid parameters or SDK not initialized | Call Initialize() first and verify IsInitialized() returns true. Check that Client ID and Client Secret are correct. |
OnAuthComplete fires with bWasSuccessful = false |
Network error, invalid credentials, or EOS service outage | Check ErrorMessage for details. Verify your EOS Client ID and Secret in the Epic Developer Portal. Ensure the player is logged into the Epic Games Launcher. |
GetExchangeCode() returns false |
Auth not completed or session expired | Ensure OnAuthComplete fired with bWasSuccessful = true before calling GetExchangeCode(). |
| Supabase login fails after successful EOS auth | EOS auth provider not enabled in Supabase, or exchange code expired | Enable the Epic Games auth provider in Supabase Dashboard under Authentication > Providers. Exchange codes are single-use and short-lived. |
LoginWithEOS OnFailure fires |
Any step in the automated flow failed | Check ErrorMessage on the FEOSAuthResult. Common causes: EOS SDK not initialized, invalid credentials, network issues, or Supabase provider not configured. |
Always check bWasSuccessful before accessing ExchangeCode, ProductUserId, or DisplayName on FEOSAuthResult. These fields are empty on failure.
Log the ErrorMessage — it contains human-readable details about what went wrong, useful for debugging and for displaying to the player.
Implement a fallback — if EOS authentication fails (e.g., the player is not using the Epic Games Launcher), fall back to email/password or anonymous Supabase authentication:
void AMyGameMode::OnLoginFailure(const FEOSAuthResult& Result)
{
UE_LOG(LogTemp, Warning, TEXT("EOS login failed: %s"), *Result.ErrorMessage);
// Fallback to anonymous auth
UAsyncLoginAnon::LoginAnonymously(this)->OnSuccess.AddUObject(
this, &AMyGameMode::OnFallbackLoginSuccess);
}
Guard with preprocessor macros — always wrap EOS code in #if WITH_EOS_SDK && SUPABASE_EOS_INTEGRATION to ensure your project compiles on all platforms and configurations where EOS may not be available.
Handle SDK lifecycle carefully — call Shutdown() when done, and never call Authenticate() after Shutdown() without re-initializing. Check IsInitialized() before any operation.
Exchange codes are single-use — once GetExchangeCode() is called, the code is consumed. If Supabase login fails, you must re-authenticate with EOS to get a new exchange code.
| Page | Description |
|---|---|
| EOS Overview | Prerequisites, setup, build configuration, and feature status |
| Presence & Social | Querying presence, friend lists, and rich presence data |
| Leaderboards | EOS leaderboard queries, score submission, and caching |
| Achievements | Achievement unlocking, progress tracking, and definitions |
| Player Data Bridge | Synchronizing data between EOS and Supabase storage |
| Security Guide | Session encryption, PII redaction, and key management |
| Database CRUD | Reading, writing, and querying data after authentication |