The API Key AuthProvider may not suit your use-case as it's designed to generate API Keys for registered users to provide an alternative way for them to call protected APIs.
To be able to model this using ServiceStack's built-in Auth API Key Auth Providers I would still have a registered AuthProvider and users representing the client that would use the API Keys.
But instead of providing User registration functionality, add them into the database manually then Generating API Keys for Existing Users.
You'll need to configure your preferred RDBMS to store the API Keys and Users in:
[assembly: HostingStartup(typeof(MyApp.ConfigureDb))]
public class ConfigureDb : IHostingStartup
{
public void Configure(IWebHostBuilder builder) => builder
.ConfigureServices((context, services) =>
services.AddSingleton<IDbConnectionFactory>(
new OrmLiteConnectionFactory(
context.Configuration.GetConnectionString("DefaultConnection"),
SqliteDialect.Provider)));
}
Configure ServiceStack's Auth Feature configured with the API Key AuthProvider:
[assembly: HostingStartup(typeof(MyApp.ConfigureAuth))]
public class ConfigureAuth : IHostingStartup
{
public void Configure(IWebHostBuilder builder) => builder
.ConfigureAppHost(appHost =>
{
appHost.Plugins.Add(new AuthFeature(() => new AuthUserSession(),
new IAuthProvider[] {
new ApiKeyAuthProvider(appHost.AppSettings) {
RequireSecureConnection = false,
SessionCacheDuration = TimeSpan.FromMinutes(10),
}
}));
});
}
Then configure an RDBMS OrmLiteAuthRepository pre-populated with the clients you want to allow access to, then generate any missing API Keys for them on startup:
[assembly: HostingStartup(typeof(MyApp.ConfigureAuthRepository))]
public class ConfigureAuthRepository : IHostingStartup
{
public void Configure(IWebHostBuilder builder) => builder
.ConfigureServices(services => services.AddSingleton<IAuthRepository>(c =>
new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>())))
.ConfigureAppHost(appHost => {
var authRepo = appHost.Resolve<IAuthRepository>();
authRepo.InitSchema();
CreateUser(authRepo, "admin@email.com", "Admin User", "p@55wOrd",
roles: new[] { RoleNames.Admin });
CreateUser(authRepo, "admin.client@email.com", "Client Admin", "p@55wOrd",
roles: new[] { "ClientAdmin", "Client" });
CreateUser(authRepo, "client@email.com", "Client User", "p@55wOrd",
roles: new[] { "Client" });
},
afterAppHostInit: appHost => {
var authProvider = (ApiKeyAuthProvider)
AuthenticateService.GetAuthProvider(ApiKeyAuthProvider.Name);
using var db = appHost.TryResolve<IDbConnectionFactory>().Open();
var userWithKeysIds = db.Column<string>(db.From<ApiKey>()
.SelectDistinct(x => x.UserAuthId)).Map(int.Parse);
// Use custom UserAuth if configured
var userIdsMissingKeys = db.Column<string>(db.From<UserAuth>()
.Where(x => userWithKeysIds.Count == 0 || !userWithKeysIds.Contains(x.Id))
.Select(x => x.Id));
var authRepo = (IManageApiKeys)appHost.TryResolve<IAuthRepository>();
foreach (var userId in userIdsMissingKeys)
{
var apiKeys = authProvider.GenerateNewApiKeys(userId);
authRepo.StoreAll(apiKeys);
}
});
// Add initial Users to the configured Auth Repository
public void CreateUser(IAuthRepository authRepo, string email, string name, string password, string[] roles)
{
if (authRepo.GetUserAuthByUserName(email) == null)
{
var newAdmin = new AppUser { Email = email, DisplayName = name };
var user = authRepo.CreateUserAuth(newAdmin, password);
authRepo.AssignRoles(user, roles);
}
}
}
This will let you protect access to different APIs using role-based auth:
[ValidateIsAdmin]
public class AdminOnly { ... }
[ValidateHasRole("ClientAdmin")]
public class ClientAdminOnly { ... }
[ValidateHasRole("Client")]
public class AnyClient { ... }
Note: The Admin is a super user role that can access any protected API
If you don't want all these Auth components for your App you'll have to create your own Custom Auth Provider that implements its own Authentication which doesn't need to use any other components as it has full control over how the request is authenticated.
You can refer to the existing ApiKeyAuthProvider.cs for a guide on how to implement an API Key IAuthWithRequest Auth Provider that validates the BearerToken in its PreAuthenticateAsync() method.