DEV Community

Cover image for Connecting Unity3D with AWS services
Alexandre Bruffa for AWS Community Builders

Posted on

16 2 1 2 2

Connecting Unity3D with AWS services

In my last articles, I realized direct integrations between Unity3D and AWS using the AWS SDK for .NET. I generally don't dive into details about how the connection between Unity3D and the AWS services is made in order to focus on the primary topic. Still, it deserves a whole article because it’s not that simple!

There are many ways to access AWS resources from Unity. In this article, I will summarize three of them: using an IAM user, using a Cognito guest user, and using a Cognito authenticated user.

General considerations: For this article, we will use the AWS SDK for .NET. Since Unity uses .NET Standard 2.1, you will need the .NET Standard 2.0 assemblies available here and unzip the file in your Unity project's Plugins folder. Since we will perform asynchronous calls, you will also need the AsyncInterfaces package.

If you prefer to watch a video instead of reading this article, here you have!

1. Using an IAM User

Suppose you want to allow a specific user (i.e., a third-party app) to upload files to one of your S3 buckets. However, you only want to give programmatic access without implementing a signup or login flow. Using an IAM user is a perfect fit in this case.

Image description

Let’s simulate the process: 

  • In the S3 console, create a new S3 private bucket. I will call mine awsresourcesbucket.

Image description

  • In the IAM console, create an IAM user with programmatic access and create a new Access Key; you will be given an Access Key and a Secret Access Key. Once created, don't forget to copy the Secret Access Key. It is shown just one time!

Image description

  • Attach a new policy to the IAM user. The policy gives the required permissions to write into the S3 bucket.

Image description

  • In Unity, build an S3 Client thanks to the IAM user's Access Key and Secret Access Key, and upload the file.
using System.Threading.Tasks;
using Amazon.S3;
using Amazon.S3.Model;
using UnityEngine;
public class UploadImageIAMUser : MonoBehaviour
{
public IAmazonS3 s3Client;
void Start()
{
AmazonS3Config s3Config = new AmazonS3Config();
s3Config.RegionEndpoint = Amazon.RegionEndpoint.USEast1;
// Building S3 client with Access Key and Secret Access Key
s3Client = new AmazonS3Client("AKIAUUCCXU7QHL2TK37P", "lXu3H7vuoi9krlVQ8LpaPDJCmEXvnhOh56t1U3tT", s3Config);
}
public async void Pick()
{
// Picking image from device
NativeGallery.GetImageFromGallery(async (path) =>
{
if (path != null)
{
// Uploading image to an S3 bucket
bool uploaded = await UploadFileAsync(s3Client, "image_uploaded_with_iam_user.jpg", path);
print($"Uploaded: {uploaded}");
}
});
}
private static async Task<bool> UploadFileAsync(IAmazonS3 client, string objectName, string filePath)
{
var request = new PutObjectRequest
{
BucketName = "awsresourcesbucket",
Key = objectName,
FilePath = filePath,
};
var response = await client.PutObjectAsync(request);
return (response.HttpStatusCode == System.Net.HttpStatusCode.OK);
}
}

Comments about the above code:

2. Using a Cognito Guest User

You may remember my last article, where I built a real-time multiplayer game with Unity3D and Amazon GameLift. The Unity client calls a Lambda function to start playing, and we want that everybody who has downloaded the game can play without being logged in. You can achieve it using guest users of a Cognito Identity Pool.

Image description

Let’s simulate it: 

  • In the Lambda console, create a simple Lambda function returning a dummy value (I will call it awsResourcesFunction). I will do it in Python, but it's up to you to choose your favorite programming language.

Image description

  • In the Cognito console, create a Cognito Identity Pool with guest access. During the Pool creation, you will be asked to create a new guest role; I will call them respectively awsResourcesIdentityPool and awsResourcesCognitoGuestRole.

Image description

Image description

  • Once the Identity Pool is created, enter the guest role and attach a new policy. The policy gives the required permissions to invoke the Lambda function we have created before.

Image description

  • In Unity, we first build the AWS Credentials thanks to the Identity Pool ID and then the Lambda Client with those credentials.
using Amazon;
using Amazon.CognitoIdentity;
using UnityEngine;
using Amazon.Lambda;
using Amazon.Lambda.Model;
using System.Threading.Tasks;
using System.Text;
public class InvokeLambdaGuestUser : MonoBehaviour
{
async void Start()
{
string invokeResult = await InvokeLambdaFunction();
print($"Invoking Lambda function: {invokeResult}");
}
private async Task<string> InvokeLambdaFunction()
{
// Building AWS Credentials
CognitoAWSCredentials credentials = new CognitoAWSCredentials(
"us-east-1:40f5ec2d-3eda-4b6f-ae9d-562a9768f17f", // Your Identity Pool ID here
RegionEndpoint.USEast1 // Your region here
);
// Building Lambda Client
AmazonLambdaClient client = new AmazonLambdaClient(credentials, RegionEndpoint.USEast1);
InvokeRequest request = new InvokeRequest
{
FunctionName = "awsResourcesFunction",
InvocationType = InvocationType.RequestResponse
};
// Invoking Lambda function
InvokeResponse response = await client.InvokeAsync(request);
if (response.FunctionError == null && response.StatusCode == 200)
{
return Encoding.ASCII.GetString(response.Payload.ToArray());
}
return "Error invoking Lambda function.";
}
}

Comments about the above code:

  • The AWS documentation indicates that the InvokeAsync function has been deprecated, but remember that we are using the .NET Standard 2.0 assemblies, so it's valid for us!
  • The InvokeAsync function is asynchronous; you can call it with the await operator inside an async function.

3. Using a Cognito Authenticated User

Now imagine that you want to allow the players of your game to upload a profile picture, but you require a login to do it. This case is a bit more complex because your game will handle guest and authenticated users. You can achieve it by creating a User Pool and adding authenticated access to our Identity Pool.

Image description

Let's try:

  • In the Cognito console, create a new User Pool. You also be asked to create an Application Client during the User Pool creation. Don't forget to enable the ALLOW_USER_PASSWORD_AUTH as authentication flow.

Image description

  • For this example, we assume we already have a user registered and confirmed. Please take a look at this article of mine to learn how to do it.

Image description

  • Then, go back to the Identity Pool we created before, click on "Add identity provider" of the Authenticated access section, choose "Amazon Cognito User Pool", and link the Cognito User Pool we have created previously.

Image description

  • Go then to "Edit role", create a new role, and attach a new policy to the role (or you can reuse the policy we created for the IAM User). The policy gives the required permissions to write into the S3 bucket.

Image description

  • In Unity, we first login to the Cognito User Pool with the user Credentials; a Token ID is returned. Then we build the AWS Credentials thanks to the Identity Pool ID, and we add the login data to the AWS Credentials: the Token ID and the User Pool Provider Name. We can finally build the S3 Client with the AWS Credentials and upload a file.
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using Amazon;
using Amazon.CognitoIdentity;
using Amazon.S3.Model;
using Amazon.S3;
using Amazon.CognitoIdentityProvider;
using Amazon.CognitoIdentityProvider.Model;
using Amazon.Runtime;
public class UploadImageAuthUser : MonoBehaviour
{
public IAmazonS3 s3Client;
private IAmazonCognitoIdentityProvider cognitoService;
// Log user on Start
async void Start()
{
cognitoService = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), RegionEndpoint.USEast1);
bool logged = await LoginAsync("Alexandre", "Alexandre2023#");
print($"User logged: {logged}");
}
public async Task<bool> LoginAsync(string userName, string password)
{
Dictionary<string, string> userData = new Dictionary<string, string>();
userData.Add("USERNAME", userName);
userData.Add("PASSWORD", password);
InitiateAuthRequest authRequest = new InitiateAuthRequest
{
AuthFlow = "USER_PASSWORD_AUTH",
AuthParameters = userData,
ClientId = "1cp50jp642njfk5hhlv4m3lg0n" // Your User Pool App ID here
};
// Loggin in
InitiateAuthResponse authResponse = await cognitoService.InitiateAuthAsync(authRequest);
if (authResponse.HttpStatusCode != System.Net.HttpStatusCode.OK)
{
return false;
}
// Storing the Token ID locally
string idToken = authResponse.AuthenticationResult.IdToken;
// Building AWS Credentials
CognitoAWSCredentials credentials = new CognitoAWSCredentials(
"us-east-1:40f5ec2d-3eda-4b6f-ae9d-562a9768f17f", // Your Identity Pool ID here
RegionEndpoint.USEast1 // Your region here
);
// Adding login data (Provider name + Token ID) to credentials
credentials.AddLogin("cognito-idp.us-east-1.amazonaws.com/us-east-1_uafopeRFS", idToken);
// Building S3 client
s3Client = new AmazonS3Client(credentials, RegionEndpoint.USEast1);
return true;
}
public async void Pick()
{
NativeGallery.GetImageFromGallery(async (path) =>
{
if (path != null)
{
// Uploading image to an S3 bucket
bool uploaded = await UploadFileAsync(s3Client, "image_uploaded_with_auth_user.jpg", path);
print($"Uploaded: {uploaded}");
}
});
}
public static async Task<bool> UploadFileAsync(IAmazonS3 client, string objectName, string filePath)
{
PutObjectRequest request = new PutObjectRequest
{
BucketName = "awsresourcesbucket",
Key = objectName,
FilePath = filePath,
};
PutObjectResponse response = await client.PutObjectAsync(request);
return (response.HttpStatusCode == System.Net.HttpStatusCode.OK);
}
}

Comments about the above code:

  • We log in to the Cognito User Pool thanks to the InitiateAuthAsync function.
  • We add the login data to the AWS Credentials thanks to the AddLogin function.
  • The Provider Name is the concatenation of the following: cognito-idp. + region + .amazonaws.com/ + Cognito User Pool ID.

Final Thoughts

Connecting Unity3D with AWS services is challenging work; I hope that this article could help you!

All ids and tokens shown in this article are fake or expired; if you try to use them, you will not be able to establish any connections.

Every code of this article has been tested using Unity 2021.3.3 and Visual Studio Community 2022 for Mac. The mobile device I used to run the Unity app is a Galaxy Tab A7 Lite with Android 11.

A special thanks to Gianca Chavest for designing the fantastic illustration.

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

Top comments (3)

Collapse
 
dayvid_jones_0d3802e17fa9 profile image
Dayvid Jones

How would I download the image? I've tried using GetObjectAsync but I get "Access Denied". I've tried adding this to the policy "Action": [
"s3:PutObject",
"s3:GetObject",
"s3:GetBucketTagging",
"s3:ListBucket",
"s3:DeleteObject",
"s3:GetBucketAcl"
]
But that didn't work. Any tips?

Collapse
 
farmerinatechstack profile image
Hassan Karaouni

Thanks Alexandre - always love your shares on AWS with Unity!

Collapse
 
alexandrebruffa profile image
Alexandre Bruffa

Hi Hassan, I missed this comment! Thanks a lot!

Best Practices for Running  Container WordPress on AWS (ECS, EFS, RDS, ELB) using CDK cover image

Best Practices for Running Container WordPress on AWS (ECS, EFS, RDS, ELB) using CDK

This post discusses the process of migrating a growing WordPress eShop business to AWS using AWS CDK for an easily scalable, high availability architecture. The detailed structure encompasses several pillars: Compute, Storage, Database, Cache, CDN, DNS, Security, and Backup.

Read full post

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay