Skip to content

Commit

Permalink
Added custom login for Apple Game Center and Google Play Games
Browse files Browse the repository at this point in the history
  • Loading branch information
oliexe committed Jul 7, 2024
1 parent bf1a8e3 commit 58771d3
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 60 deletions.
6 changes: 5 additions & 1 deletion Assets/Stash/Scripts/Core/StashConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ public class StashConstants

//Account Linking
public const string LinkAccount = "/sdk/link_code/link";
public const string CustomLogin = "/sdk/custom_login/approve_with_jwt";
public const string LinkAppleGameCenter = "/sdk/link_code/link_apple_game_center";
public const string LinkGooglePlayGames = "/sdk/link_code/link_google_play";

//Custom Login
public const string CustomLogin = "/sdk/custom_login/approve_with_jwt";
public const string LoginAppleGameCenter = "/sdk/custom_login/approve_apple_game_center";
public const string LoginGooglePlayGames = "/sdk/custom_login/google_play";

}
}
190 changes: 190 additions & 0 deletions Assets/Stash/Scripts/Core/StashCustomLogin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using Stash.Core.Exceptions;
using Stash.Models;
using Stash.Scripts.Core;

namespace Stash.Core
{
/// <summary>
/// Sign in to a Stash web shop using custom auth provider.
/// For linking to Stash account, use StashLink.
/// </summary>

public static class StashCustomLogin
{
/// <summary>
/// Log in to stash account created using 3rd party authentication provider.
/// For use with bespoke login provider. Not intended for general account linking.
/// </summary>
/// <param name="code">Stash code challenge from the log in deeplink.</param>
/// <param name="playerId">Player identification, that will be used to identify purchases.</param>
/// <param name="idToken">Valid identification token (OICD) of the player.</param>
/// <param name="profileImageUrl">URL to the player's profile image/avatar to be displayed during login and on web shop.</param>
/// <returns>Returns a confirmation response, or throws StashAPIRequestError if fails.</returns>
public static async Task<LinkResponse> CustomLogin(string code, string playerId, string idToken, string profileImageUrl, StashEnvironment environment = StashEnvironment.Test)
{
// Create the authorization header with the access token
RequestHeader authorizationHeader = new()
{
Key = "Authorization",
Value = "Bearer " + idToken
};

// Create the request body with the challenge and internal user id
var requestBody = new CustomLoginBody()
{
code = code,
user = new CustomLoginBody.User
{
id = playerId,
profile_image_url = profileImageUrl
}
};

// Set the URL for the link account endpoint
string requestUrl = environment.GetRootUrl() + StashConstants.CustomLogin;
// Make a POST request to link the access token
Response result = await RestClient.Post(requestUrl, JsonUtility.ToJson(requestBody), new List<RequestHeader> { authorizationHeader });

// Check the response status code
if (result.StatusCode == 200)
{
try
{
// Parse the response data into a LinkResponse object
LinkResponse resultResponse = JsonUtility.FromJson<LinkResponse>(result.Data);
return resultResponse;
}
catch
{
// Throw an error if there is an issue parsing the response data
throw new StashParseError(result.Data);
}
}
else
{
// Throw an error if the API request was not successful
throw new StashRequestError(result.StatusCode, result.Data);
}
}

/// <summary>
/// Logs in to stash web shop via Apple Game Center account.
/// Requires a valid response (signature, salt, timestamp, publicKeyUrl) received from GameKit "fetchItems" no older than 1 hour.
/// </summary>
/// <param name="code">Stash code challenge from the deeplink.</param>
/// <param name="playerId">Player identification, that will be used to identify purchases.</param>
/// <param name="bundleId">The bundle ID of the app (CFBundleIdentifier)</param>
/// <param name="teamPlayerID">GameKit identifier for a player of all the games that you distribute using your Apple developer account.</param>
/// <param name="signature">The verification signature data that GameKit generates. (Base64 Encoded)</param>
/// <param name="salt">A random string that GameKit uses to compute the hash and randomize it. (Base64 Encoded)</param>
/// <param name="publicKeyUrl">The URL for the public encryption key.</param>
/// <param name="timestamp">The signature’s creation date and time.</param>
/// <param name="environment">Stash API environment (Defaults to Test).</param>
/// <returns>A LinkResponse object.</returns>
public static async Task<LinkResponse> LinkAppleGameCenter(string code, string playerId, string bundleId, string teamPlayerID, string signature,
string salt, string publicKeyUrl, string timestamp, StashEnvironment environment = StashEnvironment.Test)
{
// Create the request body with the challenge and internal user id
var requestBody = new LoginGameCenterBody()
{
code = code,
verification = new LoginGameCenterBody.Verification()
{
player = new LoginGameCenterBody.Player()
{
bundleId = bundleId,
teamPlayerId = teamPlayerID
},
response = new LoginGameCenterBody.Response()
{
signature = signature,
salt = salt,
publicKeyUrl = publicKeyUrl,
timestamp = timestamp
}
},
user = new LoginGameCenterBody.User()
{
id = playerId
}
};

// Set the URL for the link account endpoint
string requestUrl = environment.GetRootUrl() + StashConstants.LoginAppleGameCenter;
// Make a POST request to link the access token
Response result = await RestClient.Post(requestUrl, JsonUtility.ToJson(requestBody));

// Check the response status code
if (result.StatusCode == 200)
{
try
{
LinkResponse resultResponse = JsonUtility.FromJson<LinkResponse>(result.Data);
return resultResponse;
}
catch
{
// Throw an error if there is an issue parsing the response data
throw new StashParseError(result.Data);
}
}
else
{
// Throw an error if the API request was not successful
throw new StashRequestError(result.StatusCode, result.Data);
}
}


/// <summary>
/// Logs in to stash web shop via Google Play Games account.
/// Requires valid authorization code generated using "RequestServerSideAccess" from GooglePlayGames no older than 1 hour.
/// </summary>
/// <param name="code">Stash code challenge from the deeplink.</param>
/// <param name="playerId">Player identification, that will be used to identify purchases.</param>
/// <param name="authCode">The authorization code generated using RequestServerSideAccess</param>
/// <returns>A LinkResponse object.</returns>
public static async Task<LinkResponse> LinkGooglePlayGames(string code, string playerId, string authCode, StashEnvironment environment = StashEnvironment.Test)
{
// Create the request body with the challenge and internal user id
var requestBody = new LoginGooglePlayGamesBody()
{
code = code,
authCode = authCode,
user = new LoginGooglePlayGamesBody.User()
{
id = playerId
}
};

// Set the URL for the link account endpoint
string requestUrl = environment.GetRootUrl() + StashConstants.LoginGooglePlayGames;
// Make a POST request to link the access token
Response result = await RestClient.Post(requestUrl, JsonUtility.ToJson(requestBody));

// Check the response status code
if (result.StatusCode == 200)
{
try
{
Debug.Log("[RESPONSE RAW] " + result.Data);
LinkResponse resultResponse = JsonUtility.FromJson<LinkResponse>(result.Data);
return resultResponse;
}
catch
{
// Throw an error if there is an issue parsing the response data
throw new StashParseError(result.Data);
}
}
else
{
// Throw an error if the API request was not successful
throw new StashRequestError(result.StatusCode, result.Data);
}
}
}
}
3 changes: 3 additions & 0 deletions Assets/Stash/Scripts/Core/StashCustomLogin.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
namespace Stash.Core
{
/// <summary>
/// Linking the player's account to Stash web shop or using 3rd party authentication provider.
/// Linking the player's account to Stash Account.
/// For a custom sing in, use StashCustomLogin.
/// </summary>

public static class StashAuth
public static class StashLink
{
/// <summary>
/// Links the player's account to Stash account for Apple Account & Google Account.
Expand Down Expand Up @@ -186,60 +187,5 @@ public static async Task<LinkResponse> LinkGooglePlayGames(string challenge, str
}
}

/// <summary>
/// Log in to stash account created using 3rd party authentication provider.
/// For use with bespoke login provider. Not intended for general account linking.
/// </summary>
/// <param name="code">Stash code challenge from the log in deeplink.</param>
/// <param name="playerId">Player identification, that will be used to identify purchases.</param>
/// <param name="idToken">Valid identification token (OICD) of the player.</param>
/// <param name="profileImageUrl">URL to the player's profile image/avatar to be displayed during login and on web shop.</param>
/// <returns>Returns a confirmation response, or throws StashAPIRequestError if fails.</returns>
public static async Task<LinkResponse> CustomLogin(string code, string playerId, string idToken, string profileImageUrl, StashEnvironment environment = StashEnvironment.Test)
{
// Create the authorization header with the access token
RequestHeader authorizationHeader = new()
{
Key = "Authorization",
Value = "Bearer " + idToken
};

// Create the request body with the challenge and internal user id
var requestBody = new CustomLoginBody()
{
code = code,
user = new CustomLoginBody.User
{
id = playerId,
profile_image_url = profileImageUrl
}
};

// Set the URL for the link account endpoint
string requestUrl = environment.GetRootUrl() + StashConstants.CustomLogin;
// Make a POST request to link the access token
Response result = await RestClient.Post(requestUrl, JsonUtility.ToJson(requestBody), new List<RequestHeader> { authorizationHeader });

// Check the response status code
if (result.StatusCode == 200)
{
try
{
// Parse the response data into a LinkResponse object
LinkResponse resultResponse = JsonUtility.FromJson<LinkResponse>(result.Data);
return resultResponse;
}
catch
{
// Throw an error if there is an issue parsing the response data
throw new StashParseError(result.Data);
}
}
else
{
// Throw an error if the API request was not successful
throw new StashRequestError(result.StatusCode, result.Data);
}
}
}
}
File renamed without changes.
41 changes: 41 additions & 0 deletions Assets/Stash/Scripts/Models/LoginGameCenterBody.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;

namespace Stash.Models
{
[Serializable]
public class LoginGameCenterBody
{
public string code;
public Verification verification;
public User user;

[Serializable]
public class Verification
{
public Player player;
public Response response;
}

[Serializable]
public class Player
{
public string bundleId;
public string teamPlayerId;
}

[Serializable]
public class Response
{
public string signature;
public string salt;
public string publicKeyUrl;
public string timestamp;
}

[Serializable]
public class User
{
public string id;
}
}
}
3 changes: 3 additions & 0 deletions Assets/Stash/Scripts/Models/LoginGameCenterBody.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions Assets/Stash/Scripts/Models/LoginGooglePlayGamesBody.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace Stash.Models
{
[Serializable]
public class LoginGooglePlayGamesBody
{
public string code;
public string authCode;
public User user;

[Serializable]
public class User
{
public string id;
}
}
}
3 changes: 3 additions & 0 deletions Assets/Stash/Scripts/Models/LoginGooglePlayGamesBody.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ProjectSettings/EditorBuildSettings.asset
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ EditorBuildSettings:
serializedVersion: 2
m_Scenes:
- enabled: 1
path: Assets/Sample/Scenes/StashSample.unity
path: Assets/Stash.Sample/Scenes/StashSample.unity
guid: 9fc0d4010bbf28b4594072e72b8655ab
m_configObjects: {}
2 changes: 1 addition & 1 deletion ProjectSettings/ProjectSettings.asset
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ PlayerSettings:
clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea
templatePackageId: com.unity.template.3d@8.1.1
templateDefaultScene: Assets/Scenes/SampleScene.unity
useCustomMainManifest: 1
useCustomMainManifest: 0
useCustomLauncherManifest: 0
useCustomMainGradleTemplate: 0
useCustomLauncherGradleManifest: 0
Expand Down

0 comments on commit 58771d3

Please sign in to comment.