Function access control
Control who can invoke individual functions using an access parameter.
Read time 4 minutesLast updated 2 days ago
Within the context of Stateful Cloud Code, you control who can invoke each Cloud Code function by setting the parameter on the attribute. This parameter provides function-level authorization that restricts callers based on their relationship to the scope, for example, session membership, session host status, player ownership, or service account identity.
Access[CloudCodeFunction]Access levels
The enum defines five access levels plus a default (). Each level is either valid in any scope, or restricted to a single scope. The following table describes each value and the scope it requires:
AccessUnspecifiedLevel | Required scope | Description |
|---|---|---|
| Any | Any caller can invoke the function, regardless of session membership or ownership. |
| Any | Only service account callers can invoke the function. |
| Player | Only the owning player, whose player ID matches the scope ID, and service accounts can invoke the function. |
| MultiplayerSession | Any member of the session, including the host, and service accounts can invoke the function. |
| MultiplayerSession | Only the host of the session and service accounts can invoke the function. |
| Any | The attribute default. Cloud Code resolves the effective access from the class scope when the module loads. |
Set an access level on a function
The following code sample passes an value as the second argument to :
Access[CloudCodeFunction]using Unity.Services.CloudCode.Core;[StateScope(Scope.MultiplayerSession)]public class GameLobby{ [CloudCodeFunction("StartGame", Access.SessionHost)] public string StartGame(IExecutionContext ctx) { return $"Game started by host {ctx.PlayerId}"; } [CloudCodeFunction("GetGameState", Access.SessionMember)] public string GetGameState(IExecutionContext ctx) { return $"State requested by {ctx.PlayerId}"; } [CloudCodeFunction("ResetSeason", Access.Service)] public string ResetSeason(IExecutionContext ctx) { return "Season reset by service"; } [CloudCodeFunction("Ping", Access.Global)] public string Ping() => "pong";}
You can also omit the function name and use the method name as the endpoint. In this case, pass as the only argument:
Access[CloudCodeFunction(Access.SessionMember)]public string GetScore(IExecutionContext ctx){ return "100";}
Default access
If you don't specify an access level, the attribute defaults to . Cloud Code then resolves the effective access from the scope of the function's class when the module loads:
Access.UnspecifiedClass scope | Effective access |
|---|---|
No | |
| |
| |
Scoped functions are restricted by default. In the following code sample, doesn't declare an access level, so it resolves to , and only the owning player and service accounts can invoke it:
UpdateProfileAccess.Player[StateScope(Scope.Player)]public class PlayerProfile{ [CloudCodeFunction("UpdateProfile")] public string UpdateProfile(IExecutionContext ctx, string displayName) { return $"Profile updated for {ctx.PlayerId}"; }}
To make a function on a scoped class callable by anyone, declare explicitly.
Access.GlobalBehavior by scope type
Cloud Code enforces an access level based on the scope of the function's class.
Session-scoped functions
For -scoped classes, Cloud Code checks the caller's relationship to the multiplayer session:
MultiplayerSession- : The caller's player ID must match the session's host ID.
SessionHost - : The caller's player ID must be in the session's member list.
SessionMember
[StateScope(Scope.MultiplayerSession)]public class SessionGame{ [CloudCodeFunction("KickPlayer", Access.SessionHost)] public string KickPlayer(IExecutionContext ctx, string targetPlayerId) { return $"Player {targetPlayerId} kicked by host {ctx.PlayerId}"; } [CloudCodeFunction("SubmitMove", Access.SessionMember)] public string SubmitMove(IExecutionContext ctx, string move) { return $"Move '{move}' submitted by {ctx.PlayerId}"; }}
Player-scoped functions
For -scoped classes, use to restrict a function to the owning player. Cloud Code compares the caller's player ID with the scope ID, and denies any other player.
PlayerAccess.Player[StateScope(Scope.Player)]public class PlayerInventory{ [CloudCodeFunction("GrantItem", Access.Player)] public string GrantItem(IExecutionContext ctx, string itemId) { return $"Item {itemId} granted to {ctx.PlayerId}"; }}
Non-scoped functions
For classes without a attribute, only and are valid, because there's no scope to check the caller against.
[StateScope]GlobalServicepublic class AdminTools{ [CloudCodeFunction("MigratePlayers", Access.Service)] public string MigratePlayers(IExecutionContext ctx) { return "Migration started"; } [CloudCodeFunction("GetServerTime")] public DateTime GetServerTime() => DateTime.UtcNow;}
Error handling
When a caller doesn't have the required access level, Cloud Code returns a response with error code . The following code sample shows how to handle this error on the client side:
403 Forbidden9034try{ var result = await CloudCodeService.Instance.CallModuleEndpointAsync<string>( "GameLobby", "StartGame", scope: new CloudCodeScope(ScopeType.MultiplayerSession, sessionId));}catch (CloudCodeException ex) when (ex.ErrorCode == 9034){ Debug.Log("Access denied: you are not the session host.");}