I find myself implementing a oAuth2 AuthZServer very similar to @DylanBeatties example, except that I am creating a SS REST service to handle the requests, and creation of access_tokens. In the implementation I am using the DotNetOpenAuth library to handle the request AuthorizationServer.HandleTokenRequest(). But that method expects a FormUrlEncoded request with a bunch of form fields populated with things like: grant_type, username, password, scope etc. Which are included in my JSON request DTO.
In my ServiceStack service, how can create the FormUrlEncoded request that this library requires to work from my JSON request DTO before calling the DNOA method?
Am I going down a long rathole here? This does not feel right. But I can’t alter the functions in DotNetOpenAuth has that does the heavy lifting for me. I can’t add the necessary form fields to the existing request (readonly!). Perhaps SS can help me in some built-in way, or someone has some guidance for me for a different approach?
My goal is to have a SS REST service endpoint that creates oAuth2.0 Access tokens, and that uses the DNOA library to help me do that.
Not sure what you mean by:
"how can create the FormUrlEncoded request that this library requires to work from my JSON request DTO before calling the DNOA method?"
Do you have some example code of what you’re trying to do?
Jezz Santos:
Sure, it looks like this at the moment:
public class MyService : Service
{
public CreateAccessTokenResponse Post(CreateAccessToken body)
{
var authZServer = new AuthorizationServer(new MyOAuthZServer(…));
// Convert the request if send from Json client.
var response = authZServer.HandleTokenRequest((HttpRequestBase)this.Request.OriginalRequest);
var responseBody = response.Body.FromJson<Dictionary<string, string>>();
if (response.Status != HttpStatusCode.OK)
{
var error = (responseBody.ContainsKey(“error”)) ? responseBody[@“error”]: string.Empty;
var message = (responseBody.ContainsKey(“error_description”)) ? responseBody[@“error_description”]: error;
throw LogicErrorThrower.RuleViolation(message);
}
var accessToken = new CreateAccessTokenResponse
{
AccessToken = responseBody[@“access_token”],
RefreshToken = responseBody[@“refresh_token”],
ExpiresIn = responseBody[@“expires_in”],
TokenType = responseBody[@“token_type”],
Scope = responseBody[@“scope”]
};
this.SetResponseCode(HttpStatusCode.Created);
return accessToken;
}
}
Jezz Santos:
The problem child is the HandleTokenRequest() method that under the covers expects an ‘application/x-www-form-urlencoded’ request,and to be able to read: Form[“grant_type”], Form[“username”], Form[“password”] and other fields, from the request object passed to it. Problem is that the request is JSON, has not the right form fields (if any), and so the HandleTokenRequest() method fails with BadRequest.
I believe what I need to do (at least notionally) for this request alone, is to somehow convert or mimic the request it is expecting.
I did find an overload for HandleTokenrequest that takes a HttpRequestMessage that I can create and populate manually with the form fields. So I took this path for now. But was hoping someone else would be able to offer some wisdom on a better way to use the framework for these cases - if there is one.
A couple of things that may help, you can deserialize the JSON directly into a C# DTO by convention using the propertyConvention=PropertyConvention.Lenient which you can localize its behavior in using (JsConfig.With(…){ … } block, see:
https://github.com/ServiceStack/ServiceStack.Text/commit/376f1ffd1d70cc898380421841785b510607a18f
You can also create a mutable HttpRequestBase by overriding it and providing your own impl with mutable properties, see:
https://github.com/ServiceStack/ServiceStack/commit/5a6dc72edcd1cadd1335b8638f3b69c2021cf38e
Does this help?
Jezz Santos:
Thanks again Demis.
OK, regarding the HttpRequestBase thing, looks like this appraoch is very similar to populating a HttpRequestMessage of my own that can be accepted by the HandleTokenRequest() method. So I think I’ll stick with that for now.
You gave me the affirmation i really wanted which was that my approach is not really that off the wall, and that there was not another common way to solve this particular problem in the framework. Perhaps its a real out-lier scenario after all.
Thanks for the tip on the JsConfig thing, great to find these kinds of gems.
cheers