Skip to content

API Key AuthProvider

Demis Bellot edited this page Oct 25, 2016 · 6 revisions

This page has moved to docs.servicestack.net


The API Key Auth Provider provides an alternative method for allowing external 3rd Parties access to your protected Services without needing to specify a password. API Keys is the preferred approach for many well-known public API providers used in system-to-system scenarios for several reasons:

  • Simple - It integrates easily with existing HTTP Auth functionality
  • Independent from Password - Limits exposure to the much more sensitive master user passwords that should ideally never be stored in plain-text. Resetting User's Password or password reset strategies wont invalidate existing systems configured to use API Keys
  • Entropy - API Keys are typically much more secure than most normal User Passwords. The configurable default has 24 bytes of entropy (Guids have 16 bytes) generated from a secure random number generator that encodes to 32 chars using URL-safe Base64 (Same as Stripe)
  • Performance - Thanks to their much greater entropy and independence from user-chosen passwords, API Keys are validated as fast as possible using a datastore Index. This is contrast to validating hashed user passwords which as a goal require usage of slower and more computationally expensive algorithms to try make brute force attacks infeasible

Like most ServiceStack providers the new API Key Auth Provider is simple to use, integrates seamlessly with ServiceStack existing Auth model and includes Typed end-to-end client/server support.

For familiarity and utility we've modeled our implementation around Stripe's API Key functionality whilst sharing many of the benefits of ServiceStack's Auth Providers:

Simple and Integrated

To register ApiKeyAuthProvider add it to the AuthFeature list of Auth Providers:

Plugins.Add(new AuthFeature(...,
    new IAuthProvider[] {
        new ApiKeyAuthProvider(AppSettings),
        new CredentialsAuthProvider(AppSettings),
        //...
    }));

The ApiKeyAuthProvider works similarly to the other ServiceStack IAuthWithRequest providers where a successful API Key initializes the current IRequest with the user's Authenticated Session. It also adds the ApiKey POCO Model to the request which can be accessed with:

ApiKey apiKey = req.GetApiKey();

The ApiKey can be later inspected throughout the request pipeline to determine which API Key, Type and Environment was used.

Interoperable

Using existing HTTP Functionality makes it simple and interoperable to use with any HTTP Client even command-line clients like curl where API Keys can be specified in the Username of HTTP Basic Auth:

curl https://api.stripe.com/v1/charges -u yDOr26HsxyhpuRB3qbG07qfCmDhqutnA:

Or as a HTTP Bearer Token in the Authorization HTTP Request Header:

curl https://api.stripe.com/v1/charges -H "Authorization: Bearer yDOr26HsxyhpuRB3qbG07qfCmDhqutnA"

Both of these methods are built into most HTTP Clients. Here are a few different ways which you can send them using ServiceStack's .NET Service Clients:

var client = new JsonServiceClient(baseUrl) {
    Credentials = new NetworkCredential(apiKey, "")
};

var client = new JsonHttpClient(baseUrl) {
    BearerToken = apiKey
};

Or using the HTTP Utils extension methods:

var response = baseUrl.CombineWith("/secured").GetStringFromUrl(
    requestFilter: req => req.AddBasicAuth(apiKey, ""));
    
var response = await "https://example.org/secured".GetJsonFromUrlAsync(
    requestFilter: req => req.AddBearerToken(apiKey));

Multiple Auth Repositories

The necessary functionality to support API Keys has been implemented in the following supported Auth Repositories:

  • OrmLiteAuthRepository - Supporting most major RDBMS
  • RedisAuthRepository - Uses Redis back-end data store
  • DynamoDbAuthRepository - Uses AWS DynamoDB data store
  • InMemoryAuthRepository - Uses InMemory Auth Repository

And requires no additional configuration as it just utilizes the existing registered IAuthRepository.

Multiple API Key Types and Environments

You can specify any number of different Key Types for use in multiple environments for each user. Keys are generated upon User Registration where it generates both a live and test key for the secret Key Type by default. To also create both a "secret" and "publishable" API Key, configure it with:

Plugins.Add(new AuthFeature(...,
    new IAuthProvider[] {
        new ApiKeyAuthProvider(AppSettings) {
            KeyTypes = new[] { "secret", "publishable" },
        }
    });

If preferred, any of the API Key Provider options can instead be specified in App Settings following the apikey.{PropertyName} format, e.g:

<add key="apikey.KeyTypes" value="secret,publishable" />

Multitenancy

Thanks to the ServiceStack's trivial support for enabling Multitenancy, the minimal configuration required to register and API Key Auth Provider that persists to a LiveDb SQL Server database and also allows Services called with an Test API Key to query the alternative TestDb database instead, is just:

class AppHost : AppSelfHostBase
{
    public AppHost() : base("API Key Multitenancy Example", typeof(AppHost).Assembly) { }

    public override void Configure(Container container)
    {
        //Create and register an OrmLite DB Factory configured to use Live DB by default 
        var dbFactory = new OrmLiteConnectionFactory(
            AppSettings.GetString("LiveDb"), SqlServerDialect.Provider);

        container.Register<IDbConnectionFactory>(dbFactory);

        // Register a "TestDb" Named Connection 
        dbFactory.RegisterConnection("TestDb", 
            AppSettings.GetString("TestDb"), SqlServerDialect.Provider);

        //Tell ServiceStack you want to persist User Auth Info in SQL Server
        container.Register<IAuthRepository>(c => new OrmLiteAuthRepository(dbFactory));
        
        //Register the AuthFeature with the API Key Auth Provider 
        Plugins.Add(new AuthFeature(() => new AuthUserSession(),
            new IAuthProvider[] {
                new ApiKeyAuthProvider(AppSettings)
            });
    }
    
    public override IDbConnection GetDbConnection(IRequest req = null)
    {
        //If an API Test Key was used return DB connection to TestDb instead: 
        return req.GetApiKey()?.Environment == "test"
            ? TryResolve<IDbConnectionFactory>().OpenDbConnection("TestDb")
            : base.GetDbConnection(req);
    }
}

Now whenever a Test API Key was used to call an Authenticated Service, all base.Db Queries or AutoQuery Services will query TestDb instead.

API Key Defaults

The API Key Auth Provider has several options to customize its behavior with all but delegate Filters being able to be specified in AppSettings as well:

new ApiKeyAuthProvider 
{
    // Whether to only permit access via API Key from a secure connection. (default true)
    public bool RequireSecureConnection { get; set; }

    // Generate different keys for different environments. (default live,test)
    public string[] Environments { get; set; }

    // Different types of Keys each user can have. (default secret)
    public string[] KeyTypes { get; set; }

    // How much entropy should the generated keys have. (default 24)
    public int KeySizeBytes { get; set; }

    /// Whether to automatically expire keys. (default no expiry)
    public TimeSpan? ExpireKeysAfter { get; set; }

    // Automatically create ApiKey Table for Auth Repositories which need it. (true)
    public bool InitSchema { get; set; }

    // Change how API Key is generated
    public CreateApiKeyDelegate GenerateApiKey { get; set; }

    // Run custom filter after API Key is created
    public Action<ApiKey> CreateApiKeyFilter { get; set; }
}

Should you need to, you can access API Keys from the Auth Repository directly through the following interface:

public interface IManageApiKeys
{
    void InitApiKeySchema();

    bool ApiKeyExists(string apiKey);

    ApiKey GetApiKey(string apiKey);

    List<ApiKey> GetUserApiKeys(string userId);

    void StoreAll(IEnumerable<ApiKey> apiKeys);
}

This interface also defines what's required in order to implement API Keys support on a Custom AuthRepository.

For Auth Repositories which implement it, you can access the interface by resolving IAuthRepository from the IOC and casting it to the above interface, e.g:

var apiRepo = (IManageApiKeys)HostContext.TryResolve<IAuthRepository>();
var apiKeys = apiRepo.GetUserApiKeys(session.UserAuthId);

Built-in API Key Services

To give end-users access to their keys the API Key Auth Provider enables 2 Services: the GetApiKeys Service to return all valid User API Keys for the specified environment:

//GET /apikeys/live
var response = client.Get(new GetApiKeys { Environment = "live" }); 
response.Results.PrintDump(); //User's "live" API Keys 

And the RegenrateApiKeys Service to invalidate all current API Keys and generate new ones for the specified environment:

//POST /apikeys/regenerate/live
var response = client.Post(new RegenrateApiKeys { Environment = "live" }); 
response.Results.PrintDump(); //User's new "live" API Keys 

You can modify which built-in Services you want registered, or modify the custom routes to where you want them to be available by modifying the ServiceRoutes collection. E.g. you can prevent it from registering any Services by setting ServiceRoutes to an empty collection:

new ApiKeyAuthProvider { ServiceRoutes = new Dictionary<Type, string[]>() }

Generating API Keys for Existing Users

Whilst the API Key Auth Provider will automatically generate API Keys for new users, if you also want to add API Keys for existing users you'll need to use the ApiKeyAuthProvider to generate new keys for all users that don't have keys.

Here's a script you can add to AppHost.Configure() that lets you do that when using an OrmLiteAuthRepository which only needs to be run once:

AfterInitCallbacks.Add(host =>
{
    var authProvider = (ApiKeyAuthProvider)
        AuthenticateService.GetAuthProvider(ApiKeyAuthProvider.Name);
    using (var db = host.TryResolve<IDbConnectionFactory>().Open())
    {
        var userWithKeysIds = db.Column<string>(db.From<ApiKey>()
            .SelectDistinct(x => x.UserAuthId)).Map(int.Parse);

        var userIdsMissingKeys = db.Column<string>(db.From<UserAuth>()
            .Where(x => userWithKeysIds.Count == 0 || !userWithKeysIds.Contains(x.Id))
            .Select(x => x.Id));

        var authRepo = (IManageApiKeys)host.TryResolve<IAuthRepository>();
        foreach (var userId in userIdsMissingKeys)
        {
            var apiKeys = authProvider.GenerateNewApiKeys(userId.ToString());
            authRepo.StoreAll(apiKeys);
        }
    }
});

If using another Auth Repository backend this script will need to be modified to fetch the userIds for all users missing API Keys.



  1. Getting Started

    1. Creating your first project
    2. Create Service from scratch
    3. Your first webservice explained
    4. Example Projects Overview
    5. Learning Resources
  2. Designing APIs

    1. ServiceStack API Design
    2. Designing a REST-ful service with ServiceStack
    3. Simple Customer REST Example
    4. How to design a Message-Based API
    5. Software complexity and role of DTOs
  3. Reference

    1. Order of Operations
    2. The IoC container
    3. Configuration and AppSettings
    4. Metadata page
    5. Rest, SOAP & default endpoints
    6. SOAP support
    7. Routing
    8. Service return types
    9. Customize HTTP Responses
    10. Customize JSON Responses
    11. Plugins
    12. Validation
    13. Error Handling
    14. Security
    15. Debugging
    16. JavaScript Client Library (ss-utils.js)
  4. Clients

    1. Overview
    2. C#/.NET client
      1. .NET Core Clients
    3. Add ServiceStack Reference
      1. C# Add Reference
      2. F# Add Reference
      3. VB.NET Add Reference
      4. Swift Add Reference
      5. Java Add Reference
    4. Silverlight client
    5. JavaScript client
      1. Add TypeScript Reference
    6. Dart Client
    7. MQ Clients
  5. Formats

    1. Overview
    2. JSON/JSV and XML
    3. HTML5 Report Format
    4. CSV Format
    5. MessagePack Format
    6. ProtoBuf Format
  6. View Engines 4. Razor & Markdown Razor

    1. Markdown Razor
  7. Hosts

    1. IIS
    2. Self-hosting
    3. Messaging
    4. Mono
  8. Security

    1. Authentication
    2. Sessions
    3. Restricting Services
    4. Encrypted Messaging
  9. Advanced

    1. Configuration options
    2. Access HTTP specific features in services
    3. Logging
    4. Serialization/deserialization
    5. Request/response filters
    6. Filter attributes
    7. Concurrency Model
    8. Built-in profiling
    9. Form Hijacking Prevention
    10. Auto-Mapping
    11. HTTP Utils
    12. Dump Utils
    13. Virtual File System
    14. Config API
    15. Physical Project Structure
    16. Modularizing Services
    17. MVC Integration
    18. ServiceStack Integration
    19. Embedded Native Desktop Apps
    20. Auto Batched Requests
    21. Versioning
    22. Multitenancy
  10. Caching

  11. Caching Providers

  12. HTTP Caching 1. CacheResponse Attribute 2. Cache Aware Clients

  13. Auto Query

  14. Overview

  15. Why Not OData

  16. AutoQuery RDBMS

  17. AutoQuery Data 1. AutoQuery Memory 2. AutoQuery Service 3. AutoQuery DynamoDB

  18. Server Events

    1. Overview
    2. JavaScript Client
    3. C# Server Events Client
    4. Redis Server Events
  19. Service Gateway

    1. Overview
    2. Service Discovery
  20. Encrypted Messaging

    1. Overview
    2. Encrypted Client
  21. Plugins

    1. Auto Query
    2. Server Sent Events
    3. Swagger API
    4. Postman
    5. Request logger
    6. Sitemaps
    7. Cancellable Requests
    8. CorsFeature
  22. Tests

    1. Testing
    2. HowTo write unit/integration tests
  23. ServiceStackVS

    1. Install ServiceStackVS
    2. Add ServiceStack Reference
    3. TypeScript React Template
    4. React, Redux Chat App
    5. AngularJS App Template
    6. React Desktop Apps
  24. Other Languages

    1. FSharp
      1. Add ServiceStack Reference
    2. VB.NET
      1. Add ServiceStack Reference
    3. Swift
    4. Swift Add Reference
    5. Java
      1. Add ServiceStack Reference
      2. Android Studio & IntelliJ
      3. Eclipse
  25. Amazon Web Services

  26. ServiceStack.Aws

  27. PocoDynamo

  28. AWS Live Demos

  29. Getting Started with AWS

  30. Deployment

    1. Deploy Multiple Sites to single AWS Instance
      1. Simple Deployments to AWS with WebDeploy
    2. Advanced Deployments with OctopusDeploy
  31. Install 3rd Party Products

    1. Redis on Windows
    2. RabbitMQ on Windows
  32. Use Cases

    1. Single Page Apps
    2. HTML, CSS and JS Minifiers
    3. Azure
    4. Connecting to Azure Redis via SSL
    5. Logging
    6. Bundling and Minification
    7. NHibernate
  33. Performance

    1. Real world performance
  34. Other Products

    1. ServiceStack.Redis
    2. ServiceStack.OrmLite
    3. ServiceStack.Text
  35. Future

    1. Roadmap
Clone this wiki locally