9

The ServiceStack docs are full of examples on how to use server side implementation of authentication of a user. But how does one set the user credentials on the client side?

I use ServiceStack to consume a JSON REST service like this:

var restClient = new JsonServiceClient (baseUri);
var response = restClient.Get<MyResponse> ("/some/service");

How can I add any form of authentication to the request? The webservice I want to consume uses OAuth 1.0, but I am interested in adding custom authentication, too.

In my code, I have previously performed OAuth token exchange successfully, so I already own a valid access token and need to sign every REST request now using this access token and its token_secret.

M4N
  • 94,805
  • 45
  • 217
  • 260
Dynalon
  • 6,577
  • 10
  • 54
  • 84

2 Answers2

8

ServiceStack's AuthTests shows different ways of authenticating when using the ServiceStack Service Clients. By default BasicAuth and DigestAuth is built into the clients, e.g:

var client = new JsonServiceClient(baseUri) {
    UserName = UserName,
    Password = Password,
};

var request = new Secured { Name = "test" };
var response = client.Send<SecureResponse>(request);    

Behind the scenes ServiceStack will attempt to send the request normally but when the request is rejected and challenged by the Server the clients will automatically retry the same request but this time with the Basic/Digest Auth headers.

To skip the extra hop when you know you're accessing a secure service, you can tell the clients to always send the BasicAuth header with:

client.AlwaysSendBasicAuthHeader = true;

The alternative way to Authenticate is to make an explicit call to the Auth service (this requires CredentialsAuthProvider enabled) e.g:

var authResponse = client.Send<AuthResponse>(new Auth {
    provider = CredentialsAuthProvider.Name,
    UserName = "user",
    Password = "p@55word",
    RememberMe = true,  //important tell client to retain permanent cookies
});

var request = new Secured { Name = "test" };
var response = client.Send<SecureResponse>(request);    

After a successful call to the Auth service the client is Authenticated and if RememberMe is set, the client will retain the Session Cookies added by the Server on subsequent requests which is what enables future requests from that client to be authenticated.

mythz
  • 141,670
  • 29
  • 246
  • 390
  • Thx for your answer! I am implementing a legacy service, so I can't change the auth scheme. But I've found a way, see my answer. I must disagree with you :) OAuth can be used for webservices as well. Tomboy/Ubuntu1 uses it for note syncing. Upon setting up the sync server for the first time, it fires a browser and the user interaction/authorization is done. Upon completion, the Tomboy app (using it's own http listener) is called back and passed an access token. Once obtained, the access token can be used as presented in my answer, for all further requests in the future without interaction. – Dynalon Dec 09 '12 at 19:56
7

Answering myself, as I've found a nice way to do it using the LocalHttpWebRequestFilter hook in the JsonServiceClient:

For securing a web service with OAuth 1.0a, every http request has to send a special Authorization: header. Within this header field, a hash (signature) must be send that uses some characteristics of the request as input data, like the hostname, request url and others.

Now it seems the LocalHttpWebRequestFilter is called by ServiceStack right before the http request is made, and exposes the underlying HttpWebRequest object, where one can add extra headers and access the required fields of the request.

So my solution is now basically:

var client = new JsonServiceClient (baseUri);

client.LocalHttpWebRequestFilter += (request) => {
    // compute signature using request and a previously obtained
    //  access token 
    string authorization_header = CalculateSignature (request, access_token);
  
    request.Headers.Add ("Authorization", authorization_header);
};
var response = client.Get<MySecuredResponse> ("/my/service");

Note that I use the Devdefined.OAuth library to do all the heavy stuff in CalculateSignature(). The creation of request token, obtaining user authorization, and exchanging the request token for access token as required by OAuth is done outside of ServiceStack, before the above service calls.

Community
  • 1
  • 1
Dynalon
  • 6,577
  • 10
  • 54
  • 84
  • i'm trying to do something similar, have an asp.net client consuming a servicestack service. couple question for you on your implementation. how are u obtaining the access token? through service stack or by some other means? also, i don't see this CalculateSignature() method in Devdefined.OAuth. has it been replaced? thanks in advance for your help! – pjacko Jan 29 '13 at 02:57
  • 1
    The `CalculateSignature` is just a dummy that I placed, you would have to do the OAuth stuff there. I use DevDefined.OAuth for that. The token exchange is only done once, not on every request. I used ServiceStack+DevDefined.OAuth for the exchange. The whole project is open source, so you can take a look at it. The token exchange is done here: https://github.com/Dynalon/Rainy/blob/master/Rainy/WebService/OAuth/OAuthService.cs and the filter that checks for authorization upon each request is done here: https://github.com/Dynalon/Rainy/blob/master/Rainy/WebService/OAuth/OAuthAccessFilter.cs – Dynalon Jan 29 '13 at 09:19