Function access control
Control who can invoke individual functions using an access parameter.
Read time 4 minutesLast updated 23 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.");}