Index: binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs
===================================================================
--- binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs	(revision 416)
+++ binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs	(revision 418)
@@ -4,4 +4,5 @@
 using System.Net;
 using Utf8Json;
+using Webserver.Permissions;
 
 namespace Webserver.WebAPI {
@@ -9,8 +10,25 @@
 		private static readonly UnityEngine.Profiling.CustomSampler jsonDeserializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Deserialize");
 
+		protected readonly string[] CachedPerMethodModuleNames = new string[(int)ERequestMethod.Count];
+
 		protected AbsRestApi (string _name = null) : this(null, _name) {
 		}
 
 		protected AbsRestApi (Web _parentWeb, string _name = null) : base(_parentWeb, _name) {
+		}
+
+		protected override void RegisterPermissions () {
+			base.RegisterPermissions ();
+			
+			for (int i = 0; i < (int)ERequestMethod.Count; i++) {
+				ERequestMethod method = (ERequestMethod)i;
+
+				if (method is not (ERequestMethod.GET or ERequestMethod.PUT or ERequestMethod.POST or ERequestMethod.DELETE)) {
+					continue;
+				}
+
+				CachedPerMethodModuleNames [i] = $"webapi.{Name}:{method.ToStringCached ()}";
+				AdminWebModules.Instance.AddKnownModule (CachedPerMethodModuleNames [i], DefaultMethodPermissionLevel (method));
+			}
 		}
 
@@ -44,6 +62,6 @@
 
 			try {
-				switch (_context.Request.HttpMethod) {
-					case "GET":
+				switch (_context.Method) {
+					case ERequestMethod.GET:
 						if (inputJson != null) {
 							SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "GET_WITH_BODY");
@@ -53,5 +71,5 @@
 						HandleRestGet (_context);
 						return;
-					case "POST":
+					case ERequestMethod.POST:
 						if (!string.IsNullOrEmpty (_context.RequestPath)) {
 							SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "POST_WITH_ID");
@@ -66,5 +84,5 @@
 						HandleRestPost (_context, inputJson, jsonInputData);
 						return;
-					case "PUT":
+					case ERequestMethod.PUT:
 						if (string.IsNullOrEmpty (_context.RequestPath)) {
 							SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "PUT_WITHOUT_ID");
@@ -79,5 +97,5 @@
 						HandleRestPut (_context, inputJson, jsonInputData);
 						return;
-					case "DELETE":
+					case ERequestMethod.DELETE:
 						if (string.IsNullOrEmpty (_context.RequestPath)) {
 							SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "DELETE_WITHOUT_ID");
@@ -101,4 +119,61 @@
 		}
 
+		protected virtual void HandleRestGet (RequestContext _context) {
+			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
+		}
+
+		protected virtual void HandleRestPost (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
+			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
+		}
+
+		protected virtual void HandleRestPut (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
+			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
+		}
+
+		protected virtual void HandleRestDelete (RequestContext _context) {
+			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
+		}
+
+		public override bool Authorized (RequestContext _context) {
+			return ActiveMethodPermissionLevel (_context.Method) >= _context.PermissionLevel;
+		}
+
+		/// <summary>
+		/// Define default permission levels per HTTP method
+		/// </summary>
+		/// <param name="_method">HTTP method to return the default value for</param>
+		/// <returns>Default permission level for the given HTTP method. A value of int.MinValue means no per-method default, use per-API default</returns>
+		public virtual int DefaultMethodPermissionLevel (ERequestMethod _method) => int.MinValue;
+
+		public virtual int ActiveMethodPermissionLevel (ERequestMethod _method) {
+			string methodApiModuleName = CachedPerMethodModuleNames [(int)_method];
+
+			if (methodApiModuleName == null) {
+				return 0;
+			}
+
+			AdminWebModules.WebModule? overrideModule = AdminWebModules.Instance.GetModule (methodApiModuleName, false);
+			if (overrideModule.HasValue) {
+				return overrideModule.Value.PermissionLevel;
+			}
+
+			overrideModule = AdminWebModules.Instance.GetModule (CachedApiModuleName, false);
+			if (overrideModule.HasValue) {
+				return overrideModule.Value.PermissionLevel;
+			}
+
+			int defaultMethodPermissionLevel = DefaultMethodPermissionLevel (_method);
+			// ReSharper disable once ConvertIfStatementToReturnStatement
+			if (defaultMethodPermissionLevel != int.MinValue) {
+				return defaultMethodPermissionLevel;
+			}
+
+			return DefaultPermissionLevel ();
+		}
+
+#region Helpers
+
+		protected static readonly byte[] JsonEmptyData;
+		
 		static AbsRestApi () {
 			JsonWriter writer = new JsonWriter ();
@@ -108,25 +183,4 @@
 		}
 
-		protected virtual void HandleRestGet (RequestContext _context) {
-			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
-		}
-
-		protected virtual void HandleRestPost (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
-			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
-		}
-
-		protected virtual void HandleRestPut (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
-			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
-		}
-
-		protected virtual void HandleRestDelete (RequestContext _context) {
-			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
-		}
-
-
-#region Helpers
-
-		protected static readonly byte[] JsonEmptyData;
-		
 		protected static void PrepareEnvelopedResult (out JsonWriter _writer) {
 			WebUtils.PrepareEnvelopedResult (out _writer);
Index: binary-improvements2/WebServer/src/WebAPI/AbsWebAPI.cs
===================================================================
--- binary-improvements2/WebServer/src/WebAPI/AbsWebAPI.cs	(revision 416)
+++ binary-improvements2/WebServer/src/WebAPI/AbsWebAPI.cs	(revision 418)
@@ -1,6 +1,10 @@
+using Webserver.Permissions;
+
 namespace Webserver.WebAPI {
 	public abstract class AbsWebAPI {
 		public readonly string Name;
 		protected readonly Web ParentWeb;
+
+		protected readonly string CachedApiModuleName;
 
 		protected AbsWebAPI (string _name = null) : this(null, _name) {
@@ -10,8 +14,18 @@
 			Name = _name ?? GetType ().Name;
 			ParentWeb = _parentWeb;
+			CachedApiModuleName = $"webapi.{Name}";
+			RegisterPermissions ();
+		}
+
+		protected virtual void RegisterPermissions () {
+			AdminWebModules.Instance.AddKnownModule ($"webapi.{Name}", DefaultPermissionLevel ());
 		}
 
 		public abstract void HandleRequest (RequestContext _context);
 
+		public virtual bool Authorized (RequestContext _context) {
+			return AdminWebModules.Instance.ModuleAllowedWithLevel (CachedApiModuleName, _context.PermissionLevel);
+		}
+
 		public virtual int DefaultPermissionLevel () => 0;
 	}
