AccelByte Gaming Services and 3rd Party OpenID Connect Login Integration Using AccelByte C# (.NET) Extend SDK
AccelByte Gaming Services provides integration with OpenID Connect providers as one of the 3rd party login integration options. Any OpenID Connect providers should work. The following sample app will show you how to do this with AccelByte C# Extend SDK and PhantAuth installation (an OpenID Connect provider to simplify testing). Use this image to deploy local phantauth installation in local environment using docker.
- Clone AccelByte C# Extend SDK
- Go to samples/AccelByte.Sdk.Sample.OIDC.Web folder
- Follow the README.md to setup and use the sample application
sequenceDiagram
actor U as User
participant I as Web Browser
participant A as Sample App
participant P as OIDC Provider
participant B as AB Cloud IAM Service
U ->>+ I: Open Index Page
I ->>+ A: Get index.html
A -->>- I:
I ->>+ A: Get Provider List (provider.json)
A -->>- I:
I -->>- U:
U ->>+ I: Click Provider Login Button
I ->>+ P: Get OIDC Client Configuration via Discovery URL
P -->>- I:
I ->>+ P: Get OIDC Provider Login Page
P -->>- I:
I -->>- U:
U ->>+ I: Login
I ->>+ P: Perform Login
P -->>- I:
I -->>+ A: Call Callback URL
A ->>+ P: Authorize Access Token
P -->>- A:
A ->>+ B: Platform Login
B -->>- A:
A -->>- I:
I -->>- U:
In index.html
:
This function is to get config from discovery url and after the config is retrieved, it creates an OidcClient
object. Note that the response_type
is code, as we want to get the access code to be authorized later.
function discoverOidConfigAndCreateClient(config, onCreated) {
$.ajax({
url: config.discovery_url,
method: 'GET',
success: function (dResp) {
var oidcClient = new Oidc.OidcClient({
authority: dResp.issuer,
client_id: config.client_id,
redirect_uri: (window.location.href + 'callback?provider=' + config.key),
response_type: "code",
scope: config.scope,
filterProtocolClaims: false,
loadUserInfo: false
});
if (onCreated != undefined)
onCreated(oidcClient, dResp);
}
});
}
And this code shows the usage of the above function and uses the OidcClient
object to make a sign-in request and redirect the web page to the provider's login page.
discoverOidConfigAndCreateClient(config, function (client, discData) {
client.createSigninRequest({
state: {
bar: Math.random()
}
}).then(function (req) {
window.location = req.url;
}).catch(function (err) {
console.log(err);
window.alert(err);
});
});
Processing access token received from the provider is done on the backend side. These codes shows how to receive then using plain .NET web server (kestrel)
public async Task Invoke(HttpContext context)
{
string route = (context.Request.Method.ToUpper() + " " + context.Request.Path);
if (route == "GET /callback")
{
string providerId = String.Empty;
string authCode = String.Empty;
if (context.Request.Query.ContainsKey("provider"))
providerId = context.Request.Query["provider"].ToString().Trim().ToLower();
if (context.Request.Query.ContainsKey("code"))
authCode = context.Request.Query["code"].ToString().Trim();
var dProviders = _Providers.ToDictionary();
if (!dProviders.ContainsKey(providerId))
{
context.Response.StatusCode = 400;
await context.Response.WriteAsync("UNRECOGNIZED PROVIDER");
}
ProviderSpecification spec = dProviders[providerId];
OAuthTokens tokens = GetAuthorizedToken(spec, authCode);
...
}
...
}
The provider will send authentication or access code, and by using this code, we want to authorize it so we can use the later tokens as our platform token for AccelByte. Authorizing an auth code done using this method:
protected OAuthTokens GetAuthorizedToken(ProviderSpecification spec, string authorizationToken)
{
HttpClient client = new HttpClient();
DiscoveryData dData = DiscoveryData.Retrieve(client, spec.DiscoveryUrl);
HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, dData.TokenEndpoint);
req.Content = new FormUrlEncodedContent(new Dictionary<string, string>()
{
{"grant_type", "authorization_code" },
{"client_id", spec.ClientId },
{"client_secret", spec.ClientSecret },
{"redirect_uri", "http://localhost:9090/callback" },
{"code", authorizationToken }
});
HttpResponseMessage response = client.Send(req);
string jsonString = Helper.ConvertInputStreamToString(response.Content.ReadAsStream());
return JsonSerializer.Deserialize<OAuthTokens>(jsonString)!;
}
It sends the auth code to the provider’s token endpoint with grant_type authorization_code. It will return a collection of authorized tokens. One of them is id_token
which we will use later.
These codes show how to use the id token to login to the AccelByte backend.
try
{
AccelByteSDK sdk = AccelByteSDK.Builder
.UseDefaultHttpClient()
.UseDefaultConfigRepository()
.UseDefaultTokenRepository()
.UseDefaultCredentialRepository()
.Build();
string output = String.Empty;
sdk.LoginPlatform(spec.ABPlatformId, tokens.ID, (otr) =>
{
output = JsonSerializer.Serialize(otr);
});
context.Response.StatusCode = 200;
await context.Response.WriteAsync(output);
}
catch (Exception x)
{
context.Response.StatusCode = 500;
await context.Response.WriteAsync(x.Message);
}
This uses the id_token
to Sdk’s LoginPlatform
method.
You just need to provide all of the required fields into JSON array in providers.json
.
name
will be shown in the sample application web index page.key
is the unique identifier for this provider, make sure it follows standard variable naming.discovery_url
is the url provided by the provider for the configuration. Consult their respective documentation for this value.client_id
is an identifier provided by the provider.client_secret
, similar toclient_id
, will be provided by the provider. In some cases, there are some OIDC public instances that do not use client secret value. In that case, just leave this field blank.scope
is all the scopes required by the application. For this sample app, the scopes mentioned in the sample json is enough.platform_id
is the identifier you fill in the AccelByte admin panel when registering the OIDC provider.