Maxim V. Pavlov
Maxim V. Pavlov

Reputation: 10509

Sending custom http response code from GrantResourceOwnerCredentials

When using ASP.NET WebAPI 2 OAuthAuthorizationServerProvider one can do custom credential validation within the overridden method of:

 public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)

In case an error (Db connection error, for example) occurs during the execution of this method, I would like to return at least 500 Internal Server error to a requester. I don't seem to be able to set custom status code via context.Response.StatusCode = 500; Is there a way to control the response code from this method?

Upvotes: 1

Views: 3179

Answers (1)

Giridhar Karnik
Giridhar Karnik

Reputation: 2372

Based on Greg P's original answer, with some modifications

Step1: Create a class which will act as your middleware

using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, System.Object>,
System.Threading.Tasks.Task>;

namespace SignOnAPI.Middleware.ResponseMiddleware {

public class ResponseMiddleware 
{
    AppFunc _next;
    ResponseMiddlewareOptions _options;

    public ResponseMiddleware(AppFunc nex, ResponseMiddlewareOptions options)
    {
        _next = next;
    }

    public async Task Invoke(IDictionary<string, object> environment)
    {
        var context = new OwinContext(environment);

        await _next(environment);

        if (context.Response.StatusCode == 400 && context.Response.Headers.ContainsKey("Change_Status_Code"))
        {
            //read the status code sent in the response
            var headerValues = context.Response.Headers.GetValues("Change_Status_Code");

            //replace the original status code with the new one
            context.Response.StatusCode = Convert.ToInt16(headerValues.FirstOrDefault());

            //remove the unnecessary header flag
            context.Response.Headers.Remove("Change_Status_Code");
        }
    }
}

Step2 : Create the extensions class (Can be omitted).

This step is optional, can be modified to accept options that can be passed to the middleware.

public static class ResponseMiddlewareExtensions
{
    //method name that will be used in the startup class, add additional parameter to accept middleware options if necessary
    public static void UseResponseMiddleware(this IAppBuilder app)
    {
        app.Use<ResponseMiddleware>();
    }
}

Step3: Modify GrantResourceOwnerCredentials method in your OAuthAuthorizationServerProvider implementation

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {

        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

        if (<database connection failed)
        {
            //first reject the context, to signify that the client is not valid
            context.Rejected();

            //set the error message
            context.SetError("invalid_username_or_password", "Invalid userName or password" );

            //add a new key in the header along with the statusCode you'd like to return
            context.Response.Headers.Add("Change_Status_Code", new[] { ((int)HttpStatusCode.InternalServerError).ToString() }); 
            return;
        }
    }

Step4: Use this middleware in the startup class

public void Configuration(IAppBuilder app)
{
    app.UseResponseMiddleware();

    //configure the authentication server provider
    ConfigureOAuth(app);

    //rest of your code goes here....
}

Upvotes: 2

Related Questions