Authentication Overview

Authentication Models

As of ServiceStack v8 there are 2 main Authentication Models available to ServiceStack Apps:

ASP.NET Core Identity Auth now default from ServiceStack v8

A significant change from ServiceStack v8 is the adoption of the same ASP.NET Core Identity Authentication that's configured in Microsoft's default Projects templates is also used in ServiceStack's newest Project Templates.

History of ServiceStack Authentication

ServiceStack has always maintained its own Authentication and Authorization provider model, primarily as it was the only way to provide an integrated and unified Authentication model that worked across all our supported hosting platforms, inc. .NET Framework, ASP.NET Core on .NET Framework, HttpListener and .NET (fka .NET Core).

Whilst the Authentication story in ASP.NET has undergone several cycles of changes over the years, the ServiceStack Auth Model has remained relatively consistent and stable, with no schema changes required since release whilst still providing flexible options for extending UserAuth tables and typed User Sessions.

.NET Framework considered legacy

Although the multi-platform support of the unified Authentication model has been vital for Organizations migrating their systems to .NET (Core) where ServiceStack Customers have been able to enjoy Exceptional Code reuse, it's become clear that the .NET platform (e.g. .NET 8) is the only platform that should be considered for new projects and that .NET Framework should only be considered a stable legacy platform for running existing systems on.

Given Microsoft has committed to Authentication Improvements in .NET 8 it's become more important to easily integrate ServiceStack with new and existing .NET projects to access these new features than to continue recommending ServiceStack's unified Auth Providers as the default option for new projects.

Protecting Services

Declarative Validation Attributes

The recommended way to protect your ServiceStack APIs is to continue to use the Declarative Validation attributes which are decoupled from any implementation so be safely annotated on Request DTOs without adding any implementation dependencies, where they're also accessible to Clients and UIs using the Request DTOs to invoke your APIs.

The available Typed Authorization Attributes include:

Attribute Description
[ValidateIsAuthenticated] Restrict access toAuthenticated Users only
[ValidateIsAdmin] Restrict access to Admin Users only
[ValidateHasRole] Restrict access to only Users assigned with this Role
[ValidateHasClaim] Restrict access to only Users assigned with this Claim
[ValidateHasScope] Restrict access to only Users assigned with this Scope

That can be annotated on Request DTOs to protect APIs:

[ValidateIsAuthenticated]
[ValidateIsAdmin]
[ValidateHasRole(role)]
[ValidateHasClaim(type,value)]
[ValidateHasScope(scope)]
public class Secured {}

The Authenticate attribute

The [Authenticate] Request Filter Attribute tells ServiceStack which Services needs authentication by adding it to your Service implementations, e.g:

[Authenticate]
public class SecuredService : Service
{
    public object Get(Secured request)
    {
        IAuthSession session = this.GetSession();
        return new SecuredResponse() { Test = "You're" + session.FirstName };
    }

    public object Put(Secured request)
    {
        return new SecuredResponse() { Test = "Valid!" };
    }

    public object Post(Secured request)
    {
        return new SecuredResponse() { Test = "Valid!" };
    }

    public object Delete(Secured request)
    {
        return new SecuredResponse() { Test = "Valid!" };
    }
}

If you want, that authentication is only required for GET and PUT requests for example, you have to provide some extra parameters to the Authenticate attribute.

[Authenticate(ApplyTo.Get | ApplyTo.Put)] 

RequiredRole and RequiredPermission attributes

ServiceStack also includes a built-in role & permission based authorization attributes where you can apply the [Required*] Request Filter Attributes on your Service classes to apply to all Services or limited to a single Service:

[Authenticate]
//All HTTP (GET, POST...) methods need "CanAccess"
[RequiredRole("Admin")]
[RequiredPermission("CanAccess")]
public class MyServices : Service
{
    public object Get(Secured request) {}

    [RequiredPermission("CanAdd")]
    public object Put(Secured request) {}
    
    [RequiredPermission("CanAdd")]
    public object Post(Secured request) {}
    
    [RequiredPermission("AdminRights", "CanDelete")]
    public object Delete(Secured request) {}
}

Now the client needs the permissions:

  • CanAccess to make a GET request
  • CanAccess, CanAdd to make a PUT/POST request
  • CanAccess, AdminRights and CanDelete to make a DELETE request

If instead you want to allow access to users in ANY Role or Permission use:

[RequiresAnyRole("Admin","Member")]
[RequiresAnyRole(ApplyTo.Put | ApplyTo.Post, "Admin","Owner","Member")]
[RequiresAnyPermission(ApplyTo.Delete, "AdminRights", "CanDelete")]
public class MyServices : Service
{
    public object Get(Secured request) {}
    public object Put(Secured request) {}
    public object Post(Secured request) {}
    public object Delete(Secured request) {}
}

These attributes can also be applied to Request DTOs however as they would add a dependency to ServiceStack.dll, it's recommended to

Enabling Authentication at different levels

Using the [Authenticate] Attribute

You can protect services by adding the [Authenticate] attribute on either the Action:

class MyService : Service 
{
    [Authenticate] 
    public object Get(Protected request) { ... }
}

The Request DTO

[Authenticate] 
class Protected { ... }

Or the service implementation

[Authenticate] 
class MyService : Service 
{
    public object Get(Protected request) { ... }
}

Or by inheriting from a base class

[Authenticate] 
class MyServiceBase : Service { ... }

class MyService : MyServiceBase {
    public object Get(Protected request) { ... }
}

Using a Global Request Filter

Otherwise you can use a Global Request Filter if you wanted to restrict all requests any other way, e.g something like:

GlobalRequestFiltersAsync.Add(async (req, res, requestDto) =>
{
    if (ShouldProtectRequest(requestDto)) 
    {
        await new AuthenticateAttribute().ExecuteAsync(req, res, requestDto);
    }
});

GET Authenticate Requests are disabled by default

GET /auth/{provider} requests are disabled by default to discourage sending confidential information in the URL.

The current exceptions which still allow GET requests include:

  • /auth - Used to check if a User is Authenticated
  • /auth/logout - Logging Out
  • All OAuth Providers who starts their OAuth flow by navigating to /auth/{provider}

You can allow GET Authentication requests with:

new AuthFeature {
    AllowGetAuthenticateRequests = req => true
}

Although it's recommended to change your code to use POST instead of GET requests. Otherwise you can use the IRequest req parameter to check against a white list of known requests types.