Service Gateway loses auth

I have a service A, annotated with the [Authentiate] attribute, which uses the Gateway to call another service, also annotated with the [Authentiate].

I call service A from a test (appHost inhertits from AppSelfHostBase) , using JsonServiceClient, then calling client.Send(new Authenticate... , so I’m authenticated. I get into Service A, but
when it calls Service B using the Gateway, I get unauthenticated error. This all worked until I added the [Authenticated], so the calling action itself should be fine.

I’ve looked at Service Gateway & authentication, but I don’t understand the answer. I’m only calling locally on the same machine, which in that answer just returns localGateway anyway.

Why is the gateway losing the auth somehow? Does the gateway need to logon as well – what do I do then?

The Service Gateway executes Services using the same IRequest instance which holds the Authenticated request info so it shouldn’t lose authentication.

Can you provide info on how your App is authenticated, your Service A + B implementations containing the code that calls it via the Gateway as well as the full StackTrace of the authenticated Exception, i.e. by capturing the Exception StackTrace in Service A.

I’m calling from an integration test based on AppHostBase, with the following plugins added for auth:

plugins.Add(new AuthFeature(() =>
                        new AuthUserSession(),
                        new IAuthProvider[] {
                        new CredentialsAuthProvider {SkipPasswordVerificationForInProcessRequests = true}

The SkipPassword… thing is something I tried to see if it helped, but it didn’t.
Then there’s more:

container.Register(new ServiceStack.Caching.MemoryCacheClient());
            var userRep = new InMemoryAuthRepository(); userRep.Clear();

and some CreateUser calls based off examples in the docs.
Finally this:
plugins.Add(new ServiceStack.Validation.ValidationFeature()); // needed for the DTO auth attributes to work

Service A has the Authenticate attribute on top like this:

    public class ProcessInstanceServices : Service

and nothing on the DTO (just Route).

It uses the Gateway object inside.

Service B is very much the same:

    public class TeamServices : Service, ITeamServices

and nothing on the DTO except for the regular:

    public class GetTeamMemberCandidate : IReturn<GetTeamMemberCandidateResponse>, IGet

Side note: The Gateway object is passed down from the service into a static function, just because I didn’t want all that code in the service, but that shouldn’t matter.

The call to the gateway is straight forward (lowercase gateway, because I passed it as a param to a static function as myfunc(IServiceGateway gateway):

var response = gateway.Send(new GetTeamMemberCandidate
                            TeamName = teamName

Stack trace:

  Stack Trace: 
    ServiceClientBase.ThrowWebServiceException[TResponse](Exception ex, String requestUri) line 910
    ServiceClientBase.ThrowResponseTypeException[TResponse](Object request, Exception ex, String requestUri) line 846
    ServiceClientBase.HandleResponseException[TResponse](Exception ex, Object request, String requestUri, Func`1 createWebRequest, Func`2 getResponse, TResponse& response) line 797
    ServiceClientBase.Send[TResponse](String httpMethod, String relativeOrAbsoluteUrl, Object request) line 1404
    ServiceClientBase.Post[TResponse](IReturn`1 requestDto) line 1557
    FullProcess_IntegrationTests.HeadsUpTest() line 533

  Standard Output: 
    [18:53:10 ERR] WebException
    System.Net.WebException: The remote server returned an error: (401) Unauthorized.
       at System.Net.HttpWebRequest.GetResponse()
       at ServiceStack.ServiceClientBase.Send[TResponse](String httpMethod, String relativeOrAbsoluteUrl, Object request) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.Client/ServiceClientBase.cs:line 1392

This is a WebException exception, you’re not using the in process gateway here, you’re making an external HTTP Request which needs to be authenticated as well. Did you intend to make an external HTTP request?

Where did you get your gateway instance from? Which is what also needs to be configured to be able to make Authenticated Requests. E.g. if you’re using JWT or API Keys you can transfer the BearerToken to the Service Clients and authenticate that way.

SkipPasswordVerificationForInProcessRequests can used In Process Authenticated Requests, not external HTTP Requests that’s being done here.

I did not intend to make an external request (when calling service B), just calling my own code inside the same program. The Gateway object is available inside the service by default (and I passed it to another function as lowercase gateway – as IServiceGateway type).

The client is public IServiceClient CreateClient() => new JsonServiceClient(BaseUri);.

So the call to service A should be over HTTP, as it’s an integration test (from the SS templates).
Don’t know why the GW is not in process.

Just to test, I’ve moved the Gateway right up inside Service A.
Put a breakpoint there, and got a larger stack trace.

   at ServiceStack.ServiceClientBase.ThrowWebServiceException[TResponse](Exception ex, String requestUri) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.Client/ServiceClientBase.cs:line 912
   at ServiceStack.ServiceClientBase.ThrowResponseTypeException[TResponse](Object request, Exception ex, String requestUri) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.Client/ServiceClientBase.cs:line 847
   at ServiceStack.ServiceClientBase.HandleResponseException[TResponse](Exception ex, Object request, String requestUri, Func`1 createWebRequest, Func`2 getResponse, TResponse& response) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.Client/ServiceClientBase.cs:line 799
   at ServiceStack.ServiceClientBase.Send[TResponse](String httpMethod, String relativeOrAbsoluteUrl, Object request) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.Client/ServiceClientBase.cs:line 1404
   at ServiceStack.ServiceClientBase.Get[TResponse](Object requestDto) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.Client/ServiceClientBase.cs:line 1470
   at ServiceStack.ServiceClientBase.Send[TResponse](Object request) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.Client/ServiceClientBase.cs:line 632
   at ServiceStack.ServiceGatewayExtensions.Send[TResponse](IServiceGateway client, IReturn`1 request) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.Client/ServiceGatewayExtensions.cs:line 25
   at MasterProcessServer.ServiceInterface.ProcessInstanceServices.Post(CreateProcessInstance request) in C:\Programming\MasterProcess\MasterProcess\MasterProcessServer.ServiceInterface\ProcessInstanceServices.cs:line 36
   at ServiceStack.Host.ServiceRunner`1.<ExecuteAsync>d__15.MoveNext() in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/Host/ServiceRunner.cs:line 137

Ok then don’t use a C# Service Client then which only makes HTTP Requests, use the documented base.Gateway instance from within your Service.

public object Any(GetCustomerOrders request)
    return new GetCustomerOrders {
        Customer = Gateway.Send(new GetCustomer { Id = request.Id }),
        Orders = Gateway.Send(new QueryOrders { CustomerId = request.Id })

Outside your Service you can fetch a ServiceGateway instance from HostContext.AppHost.GetServiceGateway(Request).

I’m sorry, I was being unclear. This is how I’m doing it:

JsonServiceClient —call----> Service A ----- via GW --calls —> Service B.

Of course the call to Service A will be HTTP, that’s intended, but the GW call from A to B within the same code should be in-process I believe.

It wouldn’t throw a HTTP WebException if that was the case. Use the base.Gateway instance from the docs + my answer.

I belive that’s what I’m doing:

This is Service A (called over HTTP):

    public class ProcessInstanceServices : Service
        public IProcessRepository repo { get; set; }                // auto populated by DI
        public IDateTimeProvider dateTimeProvider { get; set; }     // auto populated by DI
        public ActionFactory actionFactory { get; set; }            // auto populated by DI
        public RunLoop runLoop { get; set; }                        // auto populated by DI
        public ITriggerHub triggerHub { get; set; }                 // auto populated by DI

        /// <summary>
        /// Create Process Instance -- Instantiate a new process (of type given as parameter)
        /// </summary>
        public CreateProcessInstanceResponse Post(CreateProcessInstance request)
            var response = Gateway.Send(new GetTeamMemberCandidate
                TeamName = "hello"

Isn’t that Gateway.Send correct? I have read the documentation again and again :slight_smile:

I found the problem!! Of course on my side!

I have this in my Setup:
container.Register(c => new JsonServiceClient(BaseUri));

Sorry, and thank you very much for answering so quickly and many times!!

Yes that’s how you use it, did you override IServiceGateway then to replace it to use a Service Client?

Yeah you did, remove it and it will use the InProcess Gateway.

1 Like