3

I have a group of ServiceStack-based services that will need to authenticate with one another using OAuth2. Specifically, the services will retrieve reference tokens from an external authentication service using the OAuth2 Client Credentials Flow.

ServiceStack doesn't support direct integration with this flow (a.k.a token authentication) but I've been able to provide two different implementations which "fit" into the framework and perform the necessary authentication handshake with the authentication service.

Which of the following two implementations is recommended, or rather, not considered an abuse of ServiceStack's integration points?

Option 1: Use a request filter attribute to validate access tokens

public class TokenAuthenticateAttribute : RequestFilterAttribute
{
    public TokenAuthenticateAttribute(params string[] requiredScopes) { ... }

    public override void Execute(IHttpRequest request, IHttpResponse response, object requestDto)
    {
        // 1. Obtain access token from request header; return 401 on syntax error.
        // 2. Send token and scopes to authentication service for validation.
        // 3. If invalid, return 401/403 accordingly.
    }
}

public class Service
{
    [TokenAuthenticate("read", "write", "admin")]
    public ResponseType Post(RequestType request) { ... }

    [TokenAuthenticate("read")]
    public ResponseType Get(AnotherRequestType request) { ... }
}

NOTE: caller must get token directly from auth service or API must provide an endpoint to delegate to auth service.

Option 2: Use a custom auth provider to issue and validate access tokens

// Requires registration in AppHost: base.PlugIns.Add(...)
public class TokenAuthProvider : AuthProvider
{
    public TokenAuthProvider(params string[] requiredScopes) { ... }

    public override object Authenticate(IServiceBase authService, IAuthSession session, Auth request)
    {
        // 1. Obtain client and secret from "request" (as username and password); return 401 accordingly
        // 2. If authenticated, return access token, expiration, etc...
    }

    public override bool IsAuthorized(IAuthSession session, IOAuthTokens tokens, Auth request = null)
    {
        // 1. Obtain access token from request header (HttpContext.Current); return false syntax error.
        // 2. Send token and scopes to authentication service for validation.
        // 3. Return true/false (valid/invalid) accordingly.
    }
}

public class Service
{
    [Authenticate]
    public ResponseType Post(RequestType request) { ... }

    [Authenticate]
    public ResponseType Get(AnotherRequestType request) { ... }
}

NOTE: all methods requiring authentication now request the same scopes.

Both of these implementations are equivalent in terms of functionality (we can work around the scope differences). However, I lean towards Option 1 as the preferred choice as it doesn't require the initialization overhead of the internal ServiceStack auth and session management components. These structures are evident in the second implementation, though they are never used.

What are your thoughts?

Related question: How to do token based auth using ServiceStack

Community
  • 1
  • 1
Steve Guidi
  • 19,700
  • 9
  • 74
  • 90

1 Answers1

3

Since you're not making use of ServiceStack's built-in OAuth providers or back-end UserAuth Repositories I'd be inclined to go with Option 1 since it has the least moving parts, where essentially the token-based authentication is just a validation Request Filter - which ultimately is also just what ServiceStack's [Authenticate] Request Filter Attribute is behind-the-scenes albeit more complex since it integrates with ServiceStack's AuthProvider model.

The main difference between the 2 is that because ServiceStack doesn't know your Request Filter is an Authentication validator you wouldn't get the authentication key icon in the metadata pages to indicate which Services require Authentication.

mythz
  • 141,670
  • 29
  • 246
  • 390