107 lines
3.9 KiB
C#
107 lines
3.9 KiB
C#
using System;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Newtonsoft.Json.Linq;
|
|
using RudderSdk.Core.Models.Auth;
|
|
|
|
namespace RudderSdk.Core;
|
|
|
|
/// <summary>
|
|
/// Authentication: device login, explicit token refresh and logout.
|
|
/// Token refresh also happens automatically — see <see cref="RudderClient"/>.
|
|
/// </summary>
|
|
public sealed class AuthService
|
|
{
|
|
private readonly RudderClient _client;
|
|
|
|
internal AuthService(RudderClient client) => _client = client;
|
|
|
|
/// <summary>
|
|
/// Raised when the session state flips: after a successful login
|
|
/// (<see cref="RudderAuthState.SignedIn"/>) and after logout or a failed
|
|
/// token refresh (<see cref="RudderAuthState.SignedOut"/>).
|
|
/// </summary>
|
|
public event Action<RudderAuthState>? AuthStateChanged;
|
|
|
|
/// <summary>
|
|
/// Signs the player in with the device identifier. The returned token pair
|
|
/// is stored in the configured token store.
|
|
/// </summary>
|
|
public async Task<LoginViaDeviceResponse> LoginWithDeviceAsync(
|
|
string region,
|
|
string language,
|
|
string? nickname = null,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var response = await _client.SendAsync<LoginViaDeviceRequest, LoginViaDeviceResponse>(
|
|
"POST",
|
|
"/sdk/v1/authorization/device",
|
|
new LoginViaDeviceRequest
|
|
{
|
|
Key = _client.ProjectKey,
|
|
DeviceId = _client.DeviceIdProvider.DeviceId,
|
|
Region = region,
|
|
Language = language,
|
|
Nickname = nickname
|
|
},
|
|
cancellationToken).ConfigureAwait(false);
|
|
|
|
if (response == null || string.IsNullOrEmpty(response.AccessToken) || string.IsNullOrEmpty(response.RefreshToken))
|
|
throw new InvalidOperationException("The server returned an incomplete session.");
|
|
|
|
_client.TokenStore.SaveTokens(response.AccessToken, response.RefreshToken);
|
|
NotifySignedIn();
|
|
return response;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Signs the player in through the project's custom authorization webhook.
|
|
/// The returned token pair is stored in the configured token store.
|
|
/// </summary>
|
|
public async Task<LoginViaCustomResponse> LoginWithCustomAsync(
|
|
JToken customData,
|
|
string region,
|
|
string language,
|
|
string? nickname = null,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var response = await _client.SendAsync<LoginViaCustomRequest, LoginViaCustomResponse>(
|
|
"POST",
|
|
"/sdk/v1/authorization/custom",
|
|
new LoginViaCustomRequest
|
|
{
|
|
Key = _client.ProjectKey,
|
|
CustomData = customData,
|
|
Region = region,
|
|
Language = language,
|
|
Nickname = nickname
|
|
},
|
|
cancellationToken).ConfigureAwait(false);
|
|
|
|
if (response == null || string.IsNullOrEmpty(response.AccessToken) || string.IsNullOrEmpty(response.RefreshToken))
|
|
throw new InvalidOperationException("The server returned an incomplete session.");
|
|
|
|
_client.TokenStore.SaveTokens(response.AccessToken, response.RefreshToken);
|
|
NotifySignedIn();
|
|
return response;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Exchanges the stored refresh token for a new token pair. Concurrent
|
|
/// callers share one refresh request. Returns false when the session could
|
|
/// not be renewed; the stored tokens are cleared in that case.
|
|
/// </summary>
|
|
public Task<bool> RefreshAsync() => _client.RefreshTokensAsync();
|
|
|
|
/// <summary>Drops the stored session.</summary>
|
|
public void Logout()
|
|
{
|
|
_client.TokenStore.Clear();
|
|
NotifySignedOut();
|
|
}
|
|
|
|
internal void NotifySignedIn() => AuthStateChanged?.Invoke(RudderAuthState.SignedIn);
|
|
|
|
internal void NotifySignedOut() => AuthStateChanged?.Invoke(RudderAuthState.SignedOut);
|
|
}
|