CanClientLogin
CanClientLogin is called when a client connection reaches the approval stage, before the player is fully connected and before OnUserApprove runs. Returning a string rejects the connection with that message; returning a value of any other non-null type lets it through.
object CanClientLogin(Network.Connection connection)Parameters
| Parameter | Type | Description |
|---|---|---|
connection | Network.Connection | The network connection of the client trying to join. Use connection.userid for the Steam ID, connection.username for the display name, connection.ipaddress for the raw IP and connection.authLevel for the Steam auth level (0, 1 or 2). |
Return value
Return null to let the normal check continue into CanUserLogin and OnUserApproved. Return a string to reject the connection with that message as the kick reason. Return false to reject with the generic connection-rejected message; returning true or any other non-string non-null value skips this hook's rejection path and the client is approved.
How it works
Oxide fires this hook from its own RustCore.IOnUserApprove handler, which executes during the connection approval handshake after the permission system has already updated the user's nickname and default groups. It runs once per connection attempt, so it is a cheap place to make a join decision. The connection argument is the only source of information: connection.userid (Steam ID) and connection.username identify the player, connection.ipaddress is the raw address (strip the port yourself if you need the bare IP), and connection.authLevel tells you whether Steam authenticated the client as an admin. Returning a string rejects the client and shows that exact text to them. Returning false rejects with the default connection-rejected message; returning anything else non-null, including true, counts as approval. Returning null defers to CanUserLogin/OnUserApproved. Because the game has not created a BasePlayer yet, you cannot use player objects here, and the hook fires for every attempt, including reconnects after a timeout.
Example plugin: Ban known IPs and required-name check at login
using Network;
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("LoginGate", "RustPluginGenerator", "1.0.0")]
[Description("Rejects connections based on IP address, Steam auth level or username rules.")]
public class LoginGate : RustPlugin
{
private class PluginConfig
{
[JsonProperty("Blocked IP addresses")]
public List<string> BlockedIps = new List<string>();
[JsonProperty("Require Steam auth (authLevel >= 1)")]
public bool RequireSteamAuth = true;
[JsonProperty("Minimum username length")]
public int MinNameLength = 3;
[JsonProperty("Maximum username length")]
public int MaxNameLength = 32;
}
private PluginConfig config;
protected override void LoadDefaultConfig() => config = new PluginConfig();
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<PluginConfig>();
if (config == null) throw new Exception();
}
catch
{
PrintWarning("Configuration file is invalid, using defaults");
LoadDefaultConfig();
}
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["BlockedIp"] = "Your IP address is not permitted on this server.",
["SteamRequired"] = "You must be signed in to Steam to join this server.",
["BadName"] = "Your name does not meet this server's name policy."
}, this);
}
private string Msg(string key, string userId = null, params object[] args) => string.Format(lang.GetMessage(key, this, userId), args);
private object CanClientLogin(Connection connection)
{
if (connection == null) return null;
string rawIp = connection.ipaddress ?? string.Empty;
int colon = rawIp.IndexOf(':');
string ip = colon >= 0 ? rawIp.Substring(0, colon) : rawIp;
string userId = connection.userid.ToString();
if (config.BlockedIps != null && config.BlockedIps.Contains(ip))
{
return Msg("BlockedIp", userId);
}
if (config.RequireSteamAuth && connection.authLevel == 0)
{
return Msg("SteamRequired", userId);
}
string name = connection.username ?? string.Empty;
if (name.Length < config.MinNameLength || name.Length > config.MaxNameLength)
{
return Msg("BadName", userId);
}
return null;
}
}
}The plugin stores a config with a list of blocked IP addresses and an optional required name fragment. CanClientLogin runs while the connection is still pending, so it reads connection.ipaddress (with the port removed) and connection.username and returns a rejection string when a rule matches. Because the rejection string is shown directly to the client, it is kept short and generic. The hook is cheap and does not touch any player entity, so there is no risk of null references. Config load validates the object and rewrites defaults if the file is corrupted. No data files or timers are needed, so Unload is empty.
Common use cases
IP-based access list
Reject connections from addresses on a block list, or restrict the server to a whitelist of trusted IPs during a lockdown. Use
connection.ipaddresswith the port removed before comparing.Steam auth level requirement
Force
connection.authLevel >= 1so clients without a valid Steam session cannot join. Return a string explaining that Steam login is required before the player can connect.Custom join name policy
Block connections whose username contains disallowed characters, is empty, or exceeds a maximum length. The check happens before any player object exists, so it is fast and side-effect free.
Pitfalls
Returning true silently approves
If you return
truefrom this hook, the approval path is considered handled and the client is approved. That can bypass your own downstream checks if you also useCanUserLogin— returnnullwhen you want to allow normal processing instead.No BasePlayer is available
This hook runs before the player entity is created.
connection.useridandconnection.usernameare the only identifiers; callingBasePlayer.FindByIDwill return null, and permission lookups should use the Steam ID string from the connection.Port is part of the IP string
connection.ipaddresstypically includes the port (for example1.2.3.4:56789). Split on:before comparing against an IP list, otherwise every entry will fail to match.
Build a plugin with CanClientLogin
Describe what should happen and get a compiled plugin that uses this hook.
Edit the prompt on the next screen. 2 free plugins a month, no card.
Last updated Oct 26, 2026. Found a mistake? Email support@rustplugingenerator.com.
Build a plugin with CanClientLogin
Generate