Federated Login¶
Login Federation is Beamable's approach to integrating 3rd Party Authentication with various platforms. You can find working examples of this federation in both Steam and Discord Samples.
This Federation is always invoked In-Band and via the Login_____
, SignUp____
and Attach____
functions of the UBeamRuntime
subsystem class.
Its interface has a single function called Authenticate with the following signature:
public async Promise<FederatedAuthenticationResponse> Authenticate(string token, string challenge, string solution);
The purpose of this function is:
Map a 3rd Party token to a Unique Identifier for the user within the 3rd Party.
Most of the time, you achieve this by doing the following:
- [Game Client]: Use the 3rd Party Client SDK to get a token of sorts.
- [Game Client]: Invoke a
Login
/SignUp
/Attach
Operation and pass the following parameters:- MicroserviceName: this is the name of the Microservice (the csproj file name, in the default case).
- IdentityNamespace: this is the Federation's Federation Id. Passing this in informs Beamable which federated login to invoke as part of the account creation/attach flow.
- IdentityUserId: this is the 3rd Party's
UserId
for the user trying to login. We use this to determine if there's already a Beamable account mapped to this 3rd Party Id. - IdentityAuthToken: this is a token that for the user that can be used by the
Authenticate
function to map it back to aUserId
. - Federation Id: this is the Federation's Federation Id. Passing this in informs Beamable which federated login to invoke as part of the account creation/attach flow.
After this, the flow goes into your Authenticate
function. What that function should do, depends on whether or not you are implementing 2FA or not.
Federated Login - without 2FA¶
Setting up the Client¶
In the client:
- Initialize the SDK.
- Use the
Sign-Up - Federated Identy
node withAuto Login
passing in:- The Microservice's Id.
- The Federation's Id.
- The User Id of the Federated 3rd Party user (this would be the user's Steam Id, for example).
- A token that can be used to authenticate this user's account with the Federated 3rd Party.
It looks like this:
Writing the Microservice¶
Semantically, there are two ways the Authenticate
function can be called:
- Account Creation Time: When using
Login - Federated Identity
orSign-Up - Federated Identity
operations. - Account Attach Time: When using
Attach - Federated Identity
operation.
In both cases, what you want to do is:
- Use the 3rd Party's APIs or C# SDKs to validate the provided
token
. - Use the 3rd Party's APIs or C# SDKs to get the
UserId
for thattoken
's user. - Return
UserId
theFederatedAuthenticationResponse
.
The main different between both cases is that:
- Account Creation Time:
Context.UserId
is0
; as at this time, no account exists. - Account Attach Time:
Context.UserId
is a validGamerTag
; as you are adding an identity to an existing account.
For non-MFA flows (which are most of the Store and Console login flows) this is all that is needed. Here's an example from our Steam Demo.
public async Promise<FederatedAuthenticationResponse> Authenticate(string token, string challenge, string solution)
{
// No user made the request, which means we are trying to sign in.
var isLogin = _requestContext.UserId == 0L;
// A user made the request which means we are trying to attach the identity to the user.
var isAttach = _requestContext.UserId != 0L;
// Get the token and use whatever 3rd Party SDK to fetch the user's id and return it
return new FederatedAuthenticationResponse { user_id = my3rdPartyId, };
}
Federated Login - Multi-Factor Authentication¶
Setting up the Client¶
In the client, we start by invoking our Login - Federated Identity
operation. This operation has a sub-event that gets invoked when the microservice responds with a challenge
string we need to solve. The SDK provides you a UBeamMultiFactorLoginData
object you can store and carry around your game state so that your player can solve the challenge.
Here's an example from our Sui-Wallet integration showcase.
Once the player has solved the challenge, you can send it to the Microservice by calling Login - Commit Federated Identity
. You can see an example below where we sign the challenge before sending over the solution to our microservice.
The Login - Federated Identity
operation's Success/Error flows will run after the Success/Error flows of the Login - Commit Federated Identity
operation.
Writing the Microservice¶
Semantically, there are an additional two ways that the Authenticate function can be called:
- Without a
challenge
/solution
: This is the first part of the flow.- Here, your function should generate a
challenge
and return it in theFederatedAuthenticationResponse
. - The
UserId
inFederatedAuthenticatedResponse
should be empty in this first step. - 3rd Party SDK's that support/require 2FA will typically provide you a function to generate said challenge.
- The
challenge
is sent back to the client who should then solve it. - After solving the challenge, the client must invoke
Login
/Attach
again, but now passing in thechallenge
andsolution
.
- Here, your function should generate a
- With a
challenge
/solution
: This is the second part of the flow.- If the
solution
is not empty, theAuthenticate
function should validate it against thechallenge
. - If successful, the function should then return a valid
UserId
inFederatedAuthenticationResponse
.
- If the
The implementation looks something like this:
public async Promise<FederatedAuthenticationResponse> Authenticate(string token, string challenge, string solution)
{
// No user made the request, which means we are trying to sign in.
var isLogin = _requestContext.UserId == 0L;
// A user made the request which means we are trying to attach the identity to the user.
var isAttach = _requestContext.UserId != 0L;
// Handle the case where we are asking for a challenge to solve (`solution` is empty).
if(string.IsNullOrEmpty(solution))
{
// Return some challenge the user is expected to solve.
// The `user_id` in the response is NOT set.
return new FederatedAuthenticationResponse
{
challenge = $"Some Challenge", // The actual challenge people will need to solve
challenge_ttl = 10 // Some duration for the challenge
};
}
// Handle the case where the user has provided the challenge AND the solution
if (!string.IsNullOrEmpty(challenge) && !string.IsNullOrEmpty(solution))
{
// My code that validates the provided solution against the challenge.
return new FederatedAuthenticationResponse
{
user_id = UserIdInThirdParty
};
}
// We should never get here in a Multi-Factor Flow
throw new Exception();
}
Keep in mind that if you need multiple challenge/solution
back-and-forths between the client and the server you can do that by encoding the step in the challenge and parsing the challenge string in the client to decide at which point in the chain of challenge/solution
flow you are (this is relevant in very rare cases).