This project has moved. For the latest updates, please go here.

Implicit Flow - Reject Grant

Mar 15, 2014 at 9:16 AM
Edited Mar 15, 2014 at 9:17 AM
Hi,

I managed to get implicit flow working with Katana OAuthAuthorizationServer components. One thing that I am struggling is how to signal the cases where the resource owner rejects the grant.

If the implicit flow request is valid (client_id, redirect_url, etc.), the request arrives at the concent screen (ASP.NET MVC part of the application):
@model AuthorizeViewModel
@{
    ViewBag.Title = "Concent Screen";
}

<h2>@Model.Application.Name</h2>
<div class="lead">
    @Model.Application.Description
</div>

<div>
    The <strong>@Model.Client.Name</strong> application wants your concent to act on behalf of you (as <strong>@User.Identity.Name</strong>) for the following permissions:
</div>

<br />

<ul>
    @foreach (var item in Model.RequestedScopes)
    {
        <li>
            @item
        </li>
    }
</ul>

<br />

<div>
    <div class="pull-left">
        @using (Html.BeginForm())
        {
            @Html.AntiForgeryToken()
            <input type="hidden" name="isAccepted" value="true" />
            <button class="btn btn-primary" type="submit">Give Permission</button>
        }
    </div>
    <div class="pull-left" style="margin-left: 10px;">
        @using (Html.BeginForm())
        {
            @Html.AntiForgeryToken()
            <input type="hidden" name="isAccepted" value="false" />
            <button class="btn btn-danger" type="submit">Reject</button>
        }
    </div>
    <div class="clearfix"></div>
</div>
As you can see, there are two buttons there: Give Permission and Reject. Here is the corresponding controller action which handles the POST request:
    [HttpPost]
    [ActionName("Authorize")]
    [ValidateAntiForgeryToken]
    public ActionResult AuthorizePost(string app, string response_type, string redirect_uri, string client_id, bool isAccepted)
    {
        if (isAccepted)
        {
            ClaimsIdentity identity = User.Identity as ClaimsIdentity;
            Client client = OwinContext.Get<Client>(OwinConstants.ClientObjectOwinKey);
            Application application = OwinContext.Get<Application>(OwinConstants.ApplicationObjectOwinContextKey);
            string[] scopes = (OwinRequest.Query["scope"] ?? "").Split(' ');

            identity = new ClaimsIdentity(identity.Claims, "Bearer", identity.NameClaimType, identity.RoleClaimType);
            foreach (string scope in scopes)
            {
                identity.AddClaim(new Claim("urn:oauth:scope", scope));
            }

            OwinContext.Authentication.SignIn(identity);
        }
        else
        {
            // TODO: Figure out what to do here...
        }

        return Content(string.Empty);
    }
What should I do inside the else statement to signal the grant rejected result so that the OAuthAuthorizatinServer components can return the error=access_denied according to the OAuth 2.0 spec?

Thanks!
Mar 16, 2014 at 6:25 PM
Edited Mar 17, 2014 at 12:10 PM
As far as I know, that's not possible (without constructing the final redirect_uri by appending the error to the URI fragment and redirecting the user yourself, of course). Even when using a pure Katana approach to manage the whole authorization consent flow (ie. when you decide to serve the consent form directly via OWIN by extending IOAuthAuthorizationServerProvider.AuthorizeEndpoint and calling EndpointContext.RequestCompleted()), you don't have access to the validation context that would allow you to implement such a behavior.

But... there is another way to achieve that: IOAuthAuthorizationServerProvider.ValidateAuthorizeRequest allows you to implement your own validation logic before IOAuthAuthorizationServerProvider.AuthorizeEndpoint is executed by the OAuthAuthorizationServerMiddleware (and before the request is processed by the higher level framework when EndpointContext.RequestCompleted() has not been called) : thus, you can try to pick up your isAccepted parameter from the query string and call BaseValidatingContext.SetError if it doesn't equal to true. This way, OAuthAuthorizationServerHandler.SendErrorRedirectAsync will automatically take care of redirecting the user to the redirect_uri with the error value appended to the query string.

Good luck.

Edit: I had a look at OAuthAuthorizationServerHandler.SendErrorRedirectAsync and it seems to always append the error, error_description and error_uri values to the query string (and not to the URI fragment) as it has no idea of the incoming grant_type. While I'm sure this is an unwanted behavior that would need to open a new ticket - as it violates the OAuth2 specs (http://tools.ietf.org/html/rfc6749#section-4.2.2.1) - I imagine that you can, in the meantime, extract the error value from the query string in your JS app.