Search code examples
c#servicestackforms-authentication

ServiceStack API documentation in Swagger-UI behind the closed doors


I want to allow access to swagger-ui and metadata only if user is authenticated (forms auth) on our web app, but I want to allow API access all the time (API have some public methods and some which require basic auth).

So what I did is I added this route prefix for API:

public override RouteAttribute[] GetRouteAttributes(Type requestType)
{
    var routes = base.GetRouteAttributes(requestType);
    routes.Each(x => x.Path = "/API" + x.Path);
    return routes;
}

And:

ServiceRoutes = new Dictionary<Type, string[]> {
{
         typeof(AuthenticateService), new[] { "/api/auth", "/api/auth/{provider}" }
     },
}

And this as well in web config:

<location path="api">
<system.web>
  <authorization>
    <allow users="*"/>
  </authorization>
</system.web>

And the thing is that when I go to /api/ now that works fine, but when I try invoke some method, I get redirected to my login route.

Is there a way to solve this like I started, or there's a better way to protect the documentation?


Solution

  • There's no explicit option to require Authentication on metadata pages but you can use a PreRequestFilter to protect access to the /metadata and /swagger-ui pages with:

    PreRequestFilters.Add((req, res) =>
    {
        if (req.PathInfo.StartsWith("/metadata") || req.PathInfo.StartsWith("/swagger-ui"))
        {
            var session = req.GetSession();
            if (!session.IsAuthenticated)
            {
                res.StatusCode = (int)HttpStatusCode.Unauthorized;
                res.EndRequest();
            }
        }
    });
    

    And to protect access to the /openapi JSON specification if you're using Swagger 2.0 / Open API Feature you can dynamically add the [Authenticate] attribute at runtime with:

    public AppHost()
    {
        typeof(OpenApiService)
            .AddAttributes(new AuthenticateAttribute());
    }
    

    If you're using the older Swagger 1.2 Plugin you can protect access to backend Services with:

    public AppHost()
    {
        typeof(SwaggerResource)
            .AddAttributes(new AuthenticateAttribute());
        typeof(SwaggerResources)
            .AddAttributes(new AuthenticateAttribute());
    }
    

    This assumes you're using ServiceStack Authentication not ASP.NET Auth.