Edit on GitHub

Authentication and Authorization

Built into ServiceStack is a simple and extensible Authentication Model that implements standard HTTP Session Authentication where Session Cookies are used to send Authenticated Requests which reference Users Custom UserSession POCO’s in your App’s registered Caching Provider.

ServiceStack also includes a number of Auth Providers which “Authenticate per-request” in this case the Authenticated User Session is only attached to and lasts during the lifetime of the current IRequest. The implementation details of each Auth Provider are transparent to your Application where the same Attributes and APIs are used to retrieve, validate, authenticate and authorize Users.

ServiceStack’s Authentication support is encapsulated in the optional AuthFeature plugin which provides an easy way to declaratively register and configure multiple Auth Providers you want to allow in your Application. It’s highly configurable with a number of additional features like whether to enable built-in Registration for Registering new Users as well as Assign/UnAssign Roles Services that Admins can use to assign Roles/Permissions to existing users.

Highly customizable and versatile

ServiceStack’s Authentication is also highly customizable and versatile from being able to choose from the plethora of Auth Providers available or inheriting from them to create your own customized Auth Provider, inheriting AuthUserSession to use your own Custom POCO with additional info you want to maintain for your Users, storing User Sessions in any of the available Caching Providers, adding custom logic by handling any of the Auth and Session Events raised throughout the Auth lifecycle, to specifying which back-end Auth Repository you want to persist your Authenticated Users in - supporting most popular RDBMS’s and popular NoSQL data stores as seen in the high-level overview below:

High Level Overview

Authentication Overview

The AuthenticateService is the primary Service that manages Authentication which delegates to the specified Auth Provider that performs the Authentication, made available via its following endpoints:

Credentials Auth Providers

If you would like ServiceStack to manage your Apps entire Authentication and persistence of Users you would use one of the available Auth Repositories and authenticate against one of the following Auth Providers:

Provider Class Name Route Description
Credentials CredentialsAuthProvider /auth/credentials Standard Authentication using Username/Password
Basic Auth BasicAuthProvider HTTP Basic Auth Username/Password sent via HTTP Basic Auth
Digest Auth DigestAuthProvider HTTP Digest Auth Username/Password hash via HTTP Digest Auth

New Users can be created via the /register Registration Service which be enabled with:

Plugins.Add(new RegistrationFeature());

OAuth Providers

The following OAuth Providers are built into ServiceStack and can be used in both ASP.NET Core and .NET Framework Apps:

Provider Class Name Route Create OAuth App Link
Facebook FacebookAuthProvider /auth/facebook developers.facebook.com/apps
Twitter TwitterAuthProvider /auth/twitter dev.twitter.com/apps
Google GoogleAuthProvider /auth/google console.developers.google.com
GitHub GithubAuthProvider /auth/github github.com/settings/applications/new
Microsoft MicrosoftGraphAuthProvider /auth/microsoftgraph apps.dev.microsoft.com
LinkedIn LinkedInAuthProvider /auth/linkedin www.linkedin.com/secure/developer
Yammer YammerAuthProvider /auth/yammer www.yammer.com/client_applications
Yandex YandexAuthProvider /auth/yandex oauth.yandex.ru/client/new
VK VkAuthProvider /auth/vkcom vk.com/editapp?act=create
Odnoklassniki OdnoklassnikiAuthProvider /auth/odnoklassniki www.odnoklassniki.ru/devaccess

Session Authentication Overview

The diagram below outlines how standard session based Authentication works and how the different providers interact in more detail:

Session Based Authentication

Where the Auth Provider are unique for each Auth Provider but otherwise adopt the same Authentication process that results in the same end result where an Authenticated AuthUserSession is persisted in the registered ICacheClient against the ss-pid Permanent Cookie if the Authenticate request RememberMe=true otherwise against ss-id Temporary Session Cookie if not.

After a Request is Authenticated its Session Cookies are sent on subsequent requests and validated by ServiceStack’s built in [Authenticate] and other [Require*] attributes to restrict access to valid users:

Session Requests

Once authenticated the Users Session can be accessed in your Services using the Typed and minimal IAuthSession APIs:

AuthUserSession session = base.SessionAs<AuthUserSession>();
IAuthSession session = base.GetSession();

Of if you’ve registered to use a Custom UserSession POCO in the AuthFeature constructor use that instead of AuthUserSession.

Typed User Sessions also accessible in all Filters and handlers that have access to the current IRequest with:

AuthUserSession session = req.SessionAs<AuthUserSession>();
IAuthSession session = req.GetSession();

See the Session docs for more info about customizing Sessions and handling different Session and Auth events.

Authentication per Request Auth Providers

These Auth Providers include authentication with each request so the Authenticated User Session is only populated on the HTTP IRequest and not saved in the registered Cache Client. Unlike traditional Auth Providers above where there is a separate “Authentication” request to establish authentication, Auth Providers that implement IAuthWithRequest instead send their Authentication “per-request” where it’s only populated on the current IRequest:

Auth with Request Auth Providers

Whilst the Authentication Process is different you’d continue to use the same APIs and Attributes to access and validate the Users Session.

The following Auth Providers below implement IAuthWithRequest and Authenticate per-request:

Provider Class Name Auth Method Description
JWT JwtAuthProvider Bearer Token Stateless Auth Provider using JSON Web Tokens
API Keys ApiKeyAuthProvider Bearer Token Allow 3rd Parties access to authenticate without a password
Basic Auth BasicAuthProvider Basic Auth Authentication using HTTP Basic Auth
Digest Auth DigestAuthProvider Digest Auth Authentication using HTTP Digest Auth

Some other special Auth Providers that Authenticate per-request include:

Integrated ASP.NET Core Authentication

The NetCoreIdentityAuthProvider is a bi-directional Authentication adapter that enables ServiceStack to use the same Authentication as the rest of your ASP.NET Core and MVC Application where it enables the following popular scenarios:

Legacy OAuth and Open ID Auth Providers

There are also a number Auth Providers have a dependency on DotNetOpenAuth that can only be used in classic ASP.NET System.Web projects:

Provider Class Name Route Create OAuth App Link
Instagram InstagramOAuth2Provider /auth/instagram instagram.com/developer/authentication
Custom OpenId OpenIdOAuthProvider /auth/openid  
My OpenId MyOpenIdOAuthProvider /auth/myopenid  
Yahoo OpenId YahooOpenIdOAuthProvider /auth/yahooopenid  

The OAuth2 Providers are in ServiceStack.Authentication.OAuth2 whilst the Open ID providers are in ServiceStack.Authentication.OpenId NuGet packages. More info available in OAuth2 and OpenId 2.0 docs. Although they should be considered legacy as DotNetOpenAuth is no longer maintained and can’t be used in ASP.NET Core projects.

Community Auth Providers

Basic Configuration

A minimal configuration needed to get Basic Authentication up and running is the following in AppHost.Config() (derived from the AuthTests unit test):

public override void Configure(Container container)
{
    Plugins.Add(new AuthFeature(() => new AuthUserSession(),
        new IAuthProvider[] { 
            new BasicAuthProvider(),       //Sign-in with HTTP Basic Auth
            new CredentialsAuthProvider(), //HTML Form post of UserName/Password credentials
        }));

    container.Register<ICacheClient>(new MemoryCacheClient());

    var userRepo = new InMemoryAuthRepository();
    container.Register<IAuthRepository>(userRepo);
    
    //The IAuthRepository is used to store the user credentials etc.
    //Implement this interface to adjust it to your app's data storage
}

AuthWebTests is a simple project that shows all Auth Providers configured and working in the same app. See the AppHost for an example of the code and the Web.config for an example of the configuration required to enable each Auth Provider.

OAuth Configuration

Once you have the ConsumerKey and ConsumerSecret you need to configure it with your ServiceStack host, via Web.config, e.g:

<add key="oauth.RedirectUrl"            value="https://yourhostname.com"/>
<add key="oauth.CallbackUrl"            value="https://yourhostname.com/auth/{0}"/>    
<add key="oauth.twitter.ConsumerKey"    value="3H1FHjGbA1N0n0aT5yApA"/>
<add key="oauth.twitter.ConsumerSecret" value="MLrZ0ujK6DwyjlRk2YLp6HwSdoBjtuqwXeHDQLv0Q"/>

For .NET Core or ASP.NET Core Apps you can add the same keys to your appsettings.json, e.g:

{
    "oauth.RedirectUrl":            "https://yourhostname.com",
    "oauth.CallbackUrl":            "https://yourhostname.com/auth/{0}",
    "oauth.twitter.ConsumerKey":    "3H1FHjGbA1N0n0aT5yApA",
    "oauth.twitter.ConsumerSecret": "MLrZ0ujK6DwyjlRk2YLp6HwSdoBjtuqwXeHDQLv0Q",
}

Each OAuth Config option fallbacks to the configuration without the provider name. If needed you provide OAuth specific configuration by including the Auth Provider Name in the configuration, e.g:

<add key="oauth.twitter.RedirectUrl"    value="https://yourhostname.com"/>
<add key="oauth.twitter.CallbackUrl"    value="https://yourhostname.com/auth/twitter"/>    

Configuration can also be specified in code when registering the Auth Provider in the AuthFeature plugin in your AppHost, e.g:

Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] {
    new TwitterAuthProvider(appSettings) { 
        RedirectUrl = "http://yourhostname.com/",
        CallbackUrl = "http://yourhostname.com/auth/twitter",
        ConsumerKey = "3H1FHjGbA1N0n0aT5yApA",
        ConsumerSecret = "MLrZ0ujK6DwyjlRk2YLp6HwSdoBjtuqwXeHDQLv0Q",
    },
}));

Note: The Callback URL in each Application should match the CallbackUrl for your application which is typically: http://yourhostname.com/auth/{Provider}, e.g. http://yourhostname.com/auth/twitter for Twitter.

User Auth Repository

The Authentication module allows you to use your own persistence back-ends but for the most part you should be able to reuse one of the existing IAuthRepository:

Registering an Auth Repository

The OrmLiteAuthRepository is the most common Auth Repository which will let you persist User Info in any of the RDBMS’s that OrmLite supports. All Auth Repositories are registered by adding a IAuthRepository dependency in your IOC, e.g:

container.Register<IDbConnectionFactory>(c =>
    new OrmLiteConnectionFactory(connectionString, SqlServer2012Dialect.Provider));

container.Register<IAuthRepository>(c =>
    new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>()));

container.Resolve<IAuthRepository>().InitSchema();

Calling InitSchema() will create the necessary RDBMS UserAuth and UserAuthDetails tables if they don’t already exist. By default the Users Roles and Permissions are blobbed on the UserAuth table, but if preferred they can optionally be maintained in a separate UserAuthRole table with:

container.Register<IAuthRepository>(c =>
    new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>()) {
        UseDistinctRoleTables = true
    });

Extending UserAuth tables

There are a number of different extensibility options for extending ServiceStack Authentication by linking to external tables with its RefId and RefIdStr fields or storing custom info in the Meta Dictionaries.

Some Auth Repositories like OrmLite also supports utilizing custom UserAuth tables with extended fields which can be configured using its generic Constructor, e.g:

public class MyUserAuth : UserAuth { .... }
public class MyUserAuthDetails : UserAuthDetails { .... }
container.Register<IAuthRepository>(c =>
    new OrmLiteAuthRepository<MyUserAuth, MyUserAuthDetails>(c.Resolve<IDbConnectionFactory>()) {
        UseDistinctRoleTables = true
    });

Session Persistence

Once authenticated the AuthUserSession model is populated and stored in the Cache using one of ServiceStack’s supported Caching providers. ServiceStack’s Sessions simply uses the ICacheClient API so any new provider added can be used for both Session and Caching, which currently includes:

The Auth Feature also allows you to specify your own custom IUserAuthSession type where you can capture additional metadata with your users session which will also get persisted and hydrated from the cache, e.g:

Plugins.Add(new AuthFeature(() => new CustomUserSession(), 
    ...
));

Note: If you’re using Custom Sessions and have JsConfig.ExcludeTypeInfo=true, you need to explicitly enable it with JsConfig<TCustomSession>.IncludeTypeInfo=true.

After authentication the client will receive a cookie with a session id, which is used to fetch the correct session from the ICacheClient internally by ServiceStack. Thus, you can access the current session in a service:

public class SecuredService : Service
{
    public object Get(Secured request)
    {
        var session = this.SessionAs<AuthUserSession>();
        return new SecuredResponse() { Test = "You're" + session.FirstName };
    }
}

ServiceStack’s Authentication, Caching and Session providers are completely new, clean, dependency-free testable APIs that doesn’t rely on and is devoid of ASP.NET’s existing membership, caching or session provider models.

World Validation

See the annotated World Validation Docs for a detailed walks through and showcases the implementation of how the most popular Server HTML rendered approaches and Client UI rendered technologies use the same built-in Authentication, Registration and protected Services.

Live Demos

To illustrate Authentication integration with ServiceStack, see the authentication-enabled Live Demos below:

.NET Core

Mobile

.NET Framework

Custom authentication and authorization

A good starting place to create your own Auth provider that relies on username/password validation is to subclass CredentialsAuthProvider and override the bool TryAuthenticate(service, username, password) method where you can provide your custom implementation. If you instead wanted to authenticate via HTTP Basic Auth you would subclass BasicAuthProvider instead.

Both the default BasicAuthProvider and CredentialsAuthProvider (which it extends) can be extended, and their behavior overwritten. An example is below:

using ServiceStack;
using ServiceStack.Auth;

public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
    public override bool TryAuthenticate(IServiceBase authService, 
        string userName, string password)
    {
        //Add here your custom auth logic (database calls etc)
        //Return true if credentials are valid, otherwise false
    }

    public override IHttpResult OnAuthenticated(IServiceBase authService, 
        IAuthSession session, IAuthTokens tokens, 
        Dictionary<string, string> authInfo)
    {
        //Fill IAuthSession with data you want to retrieve in the app eg:
        session.FirstName = "some_firstname_from_db";
        //...

        //Call base method to Save Session and fire Auth/Session callbacks:
        return base.OnAuthenticated(authService, session, tokens, authInfo);

        //Alternatively avoid built-in behavior and explicitly save session with
        //session.IsAuthenticated = true;
        //authService.SaveSession(session, SessionExpiry);
        //authService.Request.Items[Keywords.DidAuthenticate] = true;
        //return null;
    }
}

Then you need to register your custom credentials auth provider:

//Register all Authentication methods you want to enable for this web app.
Plugins.Add(new AuthFeature(() => new AuthUserSession(),
    new IAuthProvider[] {
        new CustomCredentialsAuthProvider(), //HTML Form post of User/Pass
    }
));

By default the AuthFeature plugin automatically registers the following (overridable) Service Routes:

new AuthFeature = {
  ServiceRoutes = new Dictionary<Type, string[]> {
    { typeof(AuthenticateService),  new[]{ "/auth", "/auth/{provider}" }},
    { typeof(AssignRolesService),   new[]{ "/assignroles" }},
    { typeof(UnAssignRolesService), new[]{ "/unassignroles" }},
  }
};

Assigning Roles and Permissions

Super Users with the Admin role or Requests with an AdminAuthSecret can call the built-in /assignroles and /unassignroles Services to add Roles/Permissions to existing users from an external Request, e.g:

var client = new JsonServiceClient(baseUrl);
var response = client.Post(new AssignRoles
{
    UserName = userName,
    Roles = new List<string> { "TheRole" },
    Permissions = new List<string> { "ThePermission" }
});

Inside ServiceStack you can use the AssignRoles API to add Roles and Permissions to an existing User:

var userAuth = base.AuthRepository.GetUserAuthByUserName(userName);
if (userAuth == null)
    throw HttpError.NotFound(userName);

base.AuthRepository.AssignRoles(userAuth, new[]{ "TheRole" }, new[]{ "ThePermission" });

Alternatively you can add Roles when creating a new User with:

base.AuthRepository.CreateUserAuth(new UserAuth
{
    UserName = userName,
    FirstName = "John",
    LastName = "Doe",
    DisplayName = "John Doe",
    Roles = new List<string> { "TheRole" }
}, userPassword);

You can use HostContext.AppHost.GetAuthRepository(Request) to access the registered IAuthRepository outside of a ServiceStack Service.

Logout

You can do a GET or POST to /auth/logout to logout the authenticated user or if you’re using C# client you can logout with:

client.Post(new Authenticate { provider = "logout" });

Logging out will remove the Users Session from the Server and Session Cookies from the Client and redirect to the url in Authenticate.Continue, session.ReferrerUrl, ‘Referer’ HTTP Header or AuthProvider.CallbackUrl.


Authenticating with .NET Service Clients

On the client you can use the C#/.NET Service Clients to easily consume your authenticated Services.

To authenticate using your CustomCredentialsAuthProvider by POST’ing a Authenticate Request, e.g:

var client = new JsonServiceClient(BaseUrl);

var authResponse = client.Post(new Authenticate {
    provider = CredentialsAuthProvider.Name, //= credentials
    UserName = "test@gmail.com",
    Password = "p@55w0rd",
    RememberMe = true,
});

If authentication was successful the Service Client client instance will be populated with authenticated session cookies which then allows calling Authenticated services, e.g:

var response = client.Get(new GetActiveUserId());

If you’ve also registered the BasicAuthProvider it will enable your Services to accept HTTP Basic Authentication which is built-in the Service Clients that you can populate on the Service Client with:

client.UserName = "test@gmail.com";
client.Password = "p@55w0rd";

Which will also let you access protected Services, e.g:

var response = client.Get(new GetActiveUserId());

Although behind-the-scenes it ends up making 2 requests, 1st request sends a normal request which will get rejected with a 401 Unauthorized and if the Server indicates it has the BasicAuthProvider enabled it will resend the request with the HTTP Basic Auth credentials.

You could instead save the latency of the additional auth challenge request by specifying the client should always send the Basic Auth with every request:

client.AlwaysSendBasicAuthHeader = true;

Authenticating with HTTP

To Authenticate with your CustomCredentialsAuthProvider (which inherits from CredentialsAuthProvider) you would POST:

POST localhost:60339/auth/credentials?format=json

{
    "UserName": "admin",
    "Password": "test",
    "RememberMe": true
}

When the client now tries to authenticate with the request above and the auth succeeded, the client will retrieve some cookies with a session id which identify the client on each Web Service call.

Authentication via OAuth AccessTokens

To improve OAuth Sign In integration from native Mobile or Desktop Apps you can also Authenticate via AccessTokens which can dramatically simplify the Development and User Experience by being able to leverage the Native Facebook, Twitter and Google Client SDK’s to Sign In users locally then reuse their local AccessToken to Authenticate with back-end ServiceStack Servers.

Example usage of this feature is in the Integrated Facebook, Twitter and Google Logins in Android Java Chat which is also able to Automatically Sign In users with saved AccessTokens.

This capability is available on the popular OAuth Providers below:

It can also be enabled in other OAuth2 Providers by implementing VerifyAccessToken to manually validate whether the provided AccessToken is valid with the registered OAuth App. The API to validate Access Tokens isn’t part of the OAuth2 specification and is different (and often missing) for other OAuth2 providers.

As an example, the GoogleOAuth2Provider uses a VerifyAccessToken implementation that’s similar to:

new GoogleOAuth2Provider {
    VerifyAccessToken = accessToken => {
        var url = $"https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={accessToken}";
        var json = url.GetJsonFromUrl();
        var obj = JsonObject.Parse(json);
        return obj["issued_to"] == ConsumerKey;
    }
}

Client Authentication with AccessToken

Clients can utilize this feature with the new AccessToken and AccessTokenSecret properties on the existing Authenticate request DTO, sent with the provider that the AccessToken is for, e.g:

var response = client.Post(new Authenticate {
    provider = "facebook",
    AccessToken = facebookAccessToken,
    RememberMe = true,
});

Most OAuth Providers only require sending an AccessToken with Twitter being the exception which also requires sending an AccessTokenSecret.

User Sessions Cache

ServiceStack uses the Cache Provider which was registered in the IoC container:

//Register to use an In Memory Cache Provider (default)
container.Register<ICacheClient>(new MemoryCacheClient());

//Configure an alt. distributed persisted cache, E.g Redis:
//container.Register<IRedisClientsManager>(c => 
//    new RedisManagerPool("localhost:6379"));

Tip: If you’ve got multiple servers which run the same ServiceStack service, you can use Redis to share the sessions between these servers.


Please look at SocialBootstrapApi to get a full example.

Of course you can also implement your own - custom - authentication mechanism. You aren’t forced to use the built-in ServiceStack auth mechanism.

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 permission based authorization mechanism. More details about how Roles and Permissions work is in this StackOverflow Answer.

Your request DTO can require specific permissions:

[Authenticate]
//All HTTP (GET, POST...) methods need "CanAccess"
[RequiredRole("Admin")]
[RequiredPermission("CanAccess")]
[RequiredPermission(ApplyTo.Put | ApplyTo.Post, "CanAdd")]
[RequiredPermission(ApplyTo.Delete, "AdminRights", "CanDelete")]
public class Secured
{
    public bool Test { get; set; }
} 

Now the client needs the permissions…

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

[RequiresAnyRole("Admin","Member")]
[RequiresAnyRole(ApplyTo.Post, "Admin","Owner","Member")]
[RequiresAnyPermission(ApplyTo.Delete, "AdminRights", "CanDelete")]
public class Secured
{
    public bool Test { get; set; }
} 

Normally ServiceStack calls the method bool HasPermission(string permission) in IAuthSession. This method checks if the list List<string> Permissions in IAuthSession contains the required permission.

IAuthSession is stored in a cache client as explained above

You can fill this list in the method OnAuthenticated you’ve overridden in the first part of this tutorial.

As with Authenticate, you can mark services (instead of DTO) with RequiredPermission attribute, too.

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:

GlobalRequestFilters.Add((req, res, requestDto) =>
{
    if (ShouldProtectRequest(requestDto)) 
    {
        new AuthenticateAttribute().Execute(req, res, requestDto);
    }
});

Extending UserAuth tables

Different customization and extension points and strategies to extend the UserAuth tables with your own data are explained in this StackOverflow answer.

Customizing AuthProviders

Customizing User Roles and Permissions

The default implementation of User Roles and Permissions on AuthUserSession shows how ServiceStack’s [RequiredRole] and [RequiredPermission] Roles and Permission attributes are validated:

public virtual bool HasPermission(string permission)
{
    var managesRoles = HostContext.TryResolve<IAuthRepository>() as IManageRoles;
    if (managesRoles != null)
    {
        return managesRoles.HasPermission(this.UserAuthId, permission);
    }

    return this.Permissions != null && this.Permissions.Contains(permission);
}

public virtual bool HasRole(string role)
{
    var managesRoles = HostContext.TryResolve<IAuthRepository>() as IManageRoles;
    if (managesRoles != null)
    {
        return managesRoles.HasRole(this.UserAuthId, role);
    }

    return this.Roles != null && this.Roles.Contains(role);
}

These APIs are virtual so they can be overridden in both your Custom AuthUserSession. They default to looking at the Roles and Permissions collections stored on the Session. These collections are normally sourced from the AuthUserRepository when persisting the UserAuth and UserAuthDetails POCO’s and are used to populate the UserAuthSession on successful Authentication. These collections can be further customized by AuthProviders which is what AspNetWindowsAuthProvider does to add Authenticated WindowsAuth Roles.

As seen above Roles/Permissions can instead be managed by AuthProviders that implement IManageRoles API which is what OrmLiteAuthProvider uses to look at distinct RDBMS tables to validate Roles/Permissions:

IManageRoles API

The IManageRoles API can be implemented by any IAuthRepository to provide an alternative strategy for querying and managing Users Roles and permissions.

This API is being used in the OrmLiteAuthRepository to provide an alternative way to store Roles and Permission in their own distinct table rather than being blobbed with the rest of the User Auth data. You can enable this new behavior by specifying UseDistinctRoleTables=true when registering the OrmLiteAuthRepository, e.g:

container.Register<IAuthRepository>(c =>
    new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>()) {
        UseDistinctRoleTables = true,
    });

When enabled, roles and permissions are persisted in the distinct UserAuthRole table instead of being blobbed on the UserAuth. The IAuthSession.HasRole() and IAuthSession.HasPermission() on the Users Session should be used to check if a User has a specified Role or Permission.

More examples of this are in ManageRolesTests.cs.

CustomValidationFilter

The CustomValidationFilter on all AuthProviders lets you add post verification logic after a user has signed in with an OAuth provider and their OAuth metadata is retrieved. The filter lets you return a IHttpResult to control what error response is returned, e.g:

new FacebookAuthProvider(appSettings) { 
    CustomValidationFilter = authCtx => CustomIsValid(authCtx) 
        ? authCtx.Service.Redirect(authCtx.Session.ReferrerUrl
            .AddHashParam("f","CustomErrorCode"))
        : null,
}

Or could be used to redirect a network or users to a “Not Available in your Area” page with:

Plugins.Add(new AuthFeature(..., 
    new IAuthProvider[] {
        new CredentialsAuthProvider {
            CustomValidationFilter = authCtx => 
                authCtx.Request.UserHostAddress.StartsWith("175.45.17")
                    ? HttpResult.Redirect("http://host.com/are-not-available")
                    : null
        }   
    }));

UserName Validation

The UserName validation for all Auth Repositories are configurable at:

Plugins.Add(new AuthFeature(...){
    ValidUserNameRegEx = new Regex(@"^(?=.{3,20}$)([A-Za-z0-9][._-]?)*$", RegexOptions.Compiled),
})

Instead of RegEx you can choose to validate using a Custom Predicate. The example below ensures UserNames don’t include specific chars:

Plugins.Add(new AuthFeature(...){
    IsValidUsernameFn = userName => userName.IndexOfAny(new[] { '@', '.', ' ' }) == -1
})

AccountLocked Validator

Use AccountLockedValidator to override logic to determine when an account is locked, e.g. by default an Account is Locked when it has a LockedDate but can be changed to allow locking accounts at a future date with:

new CredentialsAuthProvider {
    AccountLockedValidator = (authRepo, userAuth, tokens) => 
        userAuth.LockedDate != null && userAuth.LockedDate <= DateTime.UtcNow;
}

Alternatively if you’re using a Custom Auth Provider you can just override IsAccountLocked() to override this behavior.

Saving Extended OAuth Metadata

The new SaveExtendedUserInfo property (enabled by default) on all OAuth providers let you control whether to save the extended OAuth metadata available (into UserAuthDetails.Items) when logging in via OAuth.

MaxLoginAttempts

The MaxLoginAttempts feature lets you lock a User Account after multiple invalid login attempts, e.g:

Plugins.Add(new AuthFeature(...) {
    MaxLoginAttempts = 5   // Lock user after 5 Invalid attempts
});

Adding AuthProviders with Plugins

Plugins can register AuthProviders by calling RegisterAuthProvider() before the AuthFeature plugin is registered, which can be achieved in Plugins by having them implement IPreInitPlugin:

public class MyPlugin : IPreInitPlugin
{
    public void Configure(IAppHost appHost)
    {
        appHost.GetPlugin<AuthFeature>().RegisterAuthProvider(new MyAuthProvider());
    }
}

AuthFilterContext

Auth Providers can customize the AuthenticateResponse returned by implementing IAuthResponseFilter where it will get called back with a populated AuthFilterContext:

public class AuthFilterContext
{
    public AuthenticateService AuthService    // Instance of AuthenticateService
    public IAuthProvider AuthProvider         // Selected Auth Provider for Request
    public IAuthSession Session               // Users Session
    public Authenticate AuthRequest           // Auth Request DTO
    public AuthenticateResponse AuthResponse  // Auth Response DTO
    public bool AlreadyAuthenticated          // User was already authenticated
    public bool DidAuthenticate               // User Authenticated in this request
}

The filters can be used to modify properties on the AuthenticateResponse DTO or to completely replace what AuthenticateResponse is returned, specify a AuthFeature.AuthResponseDecorator.

ICustomUserAuth

The ICustomUserAuth interface can be implemented on User Auth Repositories that allow replacing the custom UserAuth and UserAuthDetails tables by returning the concrete Type that should be used instead:

public interface ICustomUserAuth
{
    IUserAuth CreateUserAuth();
    IUserAuthDetails CreateUserAuthDetails();
}

This allows using the same RegistrationFeature and RegisterService to handle registering new users with the substituted IUserAuth and IUserAuthDetails Types.

LoadUserAuthFilter

The LoadUserAuthFilter on AspNetWindowsAuthProvider lets you retrieve more detailed information about Windows Authenticated users during Windows Auth Authentication by using the .NET’s ActiveDirectory services, e.g:

//...
new AspNetWindowsAuthProvider(this) {
    LoadUserAuthFilter = LoadUserAuthInfo
}
//...

public void LoadUserAuthInfo(AuthUserSession userSession, 
    IAuthTokens tokens, Dictionary<string, string> authInfo)
{
    if (userSession == null) return;
    using (PrincipalContext pc = new PrincipalContext(ContextType.Domain))
    {
        var user = UserPrincipal.FindByIdentity(pc, userSession.UserAuthName);
        tokens.DisplayName = user.DisplayName;
        tokens.Email = user.EmailAddress;
        tokens.FirstName = user.GivenName;
        tokens.LastName = user.Surname;
        tokens.FullName = (String.IsNullOrWhiteSpace(user.MiddleName))
            ? "{0} {1}".Fmt(user.GivenName, user.Surname)
            : "{0} {1} {2}".Fmt(user.GivenName, user.MiddleName, user.Surname);
        tokens.PhoneNumber = user.VoiceTelephoneNumber;
    }
}

Customizable PopulateUserRoles on AspNetWindowsAuthProvider

The AspNetWindowsAuthProvider uses the public IPrincipal.IsInRole() API to determine if a User is in a particular Windows Auth role, however this can be slow when needing to query a large number of roles in LDAP as it would need to make an LDAP lookup for each role.

Performance of this can now be improved by specifying a custom PopulateUserRoles implementation that overrides how User Roles are resolved, e.g:

new AspNetWindowsAuthProvider (AppSettings) {
    PopulateUserRoles = (request, user, session) => {
        using (WindowsIdentity userId = request?.LogonUserIdentity)
        {
            List roles = new List();
            if (userId?.Groups != null)
            {
                foreach (var group in userId.Groups)
                {
                    // Remove the domain name from the name of the group, 
                    // if it has it, and you don't need it. 
                    var groupName = new SecurityIdentifier(group.Value)
                        .Translate(typeof(NTAccount)).ToString();
                    if (groupName.Contains("\")) 
                    groupName = groupName.Split('\')[1]; 
                    roles.Add(groupName);
                }
            }
            session.Roles = roles;
        }
    }
}

In Process Authenticated Requests

You can enable the CredentialsAuthProvider to allow In Process requests to Authenticate without a Password with:

new CredentialsAuthProvider {
    SkipPasswordVerificationForInProcessRequests = true,
}

When enabled this lets In Process Service Requests to login as a specified user without needing to provide their password.

For example this could be used to create an Intranet Restricted Admin-Only Service that lets you login as another user so you can debug their account without knowing their password with:

[RequiredRole("Admin")]
[Restrict(InternalOnly=true)]
public class ImpersonateUser 
{
    public string UserName { get; set; }
}

public class MyAdminServices : Service
{
    public object Any(ImpersonateUser request)
    {
        using (var service = base.ResolveService<AuthenticateService>()) //In Process
        {
            return service.Post(new Authenticate {
                provider = AuthenticateService.CredentialsProvider,
                UserName = request.UserName,
                UseTokenCookie = true, // if using JWT
            });
        }
    }
}

Your Services can use the new Request.IsInProcessRequest() to identify Services that were executed in-process.

Custom User Sessions using JWT Tokens

The JWT Auth Provider allows for a more flexible approach to impersonating users as they allow Manually creating JWT Tokens to construct a custom User Session with Custom metadata, Roles and Permissions.

IAuthMetadataProvider

An IAuthMetadataProvider provides a way to customize the authInfo in all AuthProviders. It also allows overriding of how extended Auth metadata like profileUrl is returned.

public interface IAuthMetadataProvider
{
   void AddMetadata(IAuthTokens tokens, Dictionary<string,string> authInfo);

   string GetProfileUrl(IAuthSession authSession, string defaultUrl = null);
}

To override with a custom implementation, register IAuthMetadataProvider in the IOC

PBKDF2 Password Hashing implementation

ServiceStack uses the same PBKDF2 password hashing algorithm ASP.NET Identity v3 by default for both new users and successful authentication logins where their password will automatically be re-hashed with the new implementation.

This also means if you wanted to switch, you’ll be able to import ASP.NET Identity v3 User Accounts and their Password Hashes into ServiceStack.Auth’s UserAuth tables and vice-versa.

Retain previous Password Hashing implementation

If preferred you can revert to using the existing SaltedHash implementation with:

SetConfig(new HostConfig { 
    UseSaltedHash = true
});

This also supports “downgrading” passwords that were hashed with the new IPasswordHasher provider where it will revert to using the older/weaker SaltedHash implementation on successful authentication.

Override Password Hashing Strength

The new PasswordHasher implementation can also be made to be computationally stronger or weaker by adjusting the iteration count (default 10000), e.g:

container.Register<IPasswordHasher>(new PasswordHasher(1000));

Versionable Password Hashing

The new IPasswordHasher interface includes support for versioning future Password Hashing algorithms and rehashing:

public interface IPasswordHasher
{
    // First byte marker used to specify the format used. The default implementation uses format:
    // { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey }
    byte Version { get; }

    // Returns a boolean indicating whether the providedPassword matches the hashedPassword
    // The needsRehash out parameter indicates whether the password should be re-hashed.
    bool VerifyPassword(string hashedPassword, string providedPassword, out bool needsRehash);

    // Returns a hashed representation of the supplied password
    string HashPassword(string password);
}

Which is implemented in all ServiceStack Auth Repositories where it will rehash passwords that used a different version or weaker strength, by utilizing the new API for verifying passwords:

if (userAuth.VerifyPassword(password, out var needsRehash))
{
    this.RecordSuccessfulLogin(userAuth, needsRehash, password);
    return true;
}

If you’re using a Custom Auth Repository it will need to use the new password verification APIs, please refer to OrmLiteAuthRepository for a complete concrete example.

Fallback PasswordHashers

The list of Config.FallbackPasswordHashers can be used for migrating to a new Password Hashing algorithm by registering older Password Hashing implementations that were previously used to hash Users passwords. Failed password verifications will fallback to see if the password was hashed with any of the registered FallbackPasswordHashers, if any are valid, the password attempt will succeed and the password re-hashed with the registered IPasswordHasher implementation.

Digest Auth Hashes only created when needed

Digest Auth Hashes are only populated if the DigestAuthProvider is registered. If you ever intend to support Digest access authentication in future but don’t want to register the DigestAuthProvider just yet, you can force ServiceStack to continue to maintain Digest Auth Hashes with:

new AuthFeature {
    CreateDigestAuthHashes = true
}

Users that don’t have Digest Auth Hashes will require logging in again in order to have it populated. If you don’t intend to use Digest Auth you can clear the DigestHa1Hash column in your UserAuth table which is otherwise unused.

Generate New Session Cookies on Authentication

The AuthFeature also regenerates new Session Cookies each time users login, this behavior can be disabled with:

Plugins.Add(new AuthFeature(...) {
    GenerateNewSessionCookiesOnAuthentication = false
});

ClientId and ClientSecret OAuth Config Aliases

OAuth Providers can use ClientId and ClientSecret aliases instead of ConsumerKey and ConsumerSecret, e.g:

<appSettings>
    <add key="oauth.twitter.ClientId" value="..." />
    <add key="oauth.twitter.ClientSecret" value="..." />
</appSettings>

Override Authorization HTTP Header

Request Filters can override the Authorization HTTP Header used in Auth Providers with:

httpReq.Items[Keywords.Authorization] = $"Bearer {token}";

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:

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.

Community Resources