user433342
user433342

Reputation: 1050

Return AuthenticateResult.Fail result during AddOAuth OnCreatingTicket

I want to cause oAuth to fail during the OnCreatingTicket event. I can call .Fail but it doesn't seem to do anything. Is it too late in the workflow? Am I missing some additional code to actually process the failure?

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  .AddCookie().AddOAuth("schemename", SetOAuthOptions);

private void SetOAuthOptions(OAuthOptions options)
{
    options.ClientId = ...;
    options.ClientSecret = ...;
    options.CallbackPath = ...;
    options.AuthorizationEndpoint = ...;
    options.TokenEndpoint = ...;
    options.Events = new OAuthEvents
    {
        OnCreatingTicket = async context => await AddIdentityClaimsAsync(context),
        OnTicketReceived = ...
    };
}

private async Task AddIdentityClaimsAsync(OAuthCreatingTicketContext context)
{
    ...
    if(noAccess)
        context.Fail("Sorry, you don't have access to the product.");
}

Upvotes: 4

Views: 1491

Answers (2)

Ed Downs
Ed Downs

Reputation: 386

It seems that the OAuthCreatingTicketContext.Fail doesn't end up affecting the HandleRequestResult that is ultimately returned by the authentication call. What I ended up having to do was to throw a known exception from the OnCreatingTicket handler, override OAuthHandler.HandleRemoteAuthenticateAsync to catch it and from there call HandleRequestResult.Fail with the exception.

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie().AddOAuth("schemename", SetOAuthOptions);

private void SetOAuthOptions(OAuthOptions options)
{
    options.ClientId = ...;
    options.ClientSecret = ...;
    options.CallbackPath = ...;
    options.AuthorizationEndpoint = ...;
    options.TokenEndpoint = ...;
    options.Events = new OAuthEvents
    {
        OnCreatingTicket = async context => await AddIdentityClaimsAsync(context),
        OnTicketReceived = ...
    };
}

private async Task AddIdentityClaimsAsync(OAuthCreatingTicketContext context)
{
    ...
    if(noAccess)
        throw new MyCustomException("Sorry, you don't have access to the product.");
}

// In OAuthHandler<T>
protected override async Task<HandleRequestResult> HandleRemoteAuthenticateAsync()
{    
    try
    {
        return await base.HandleRemoteAuthenticateAsync();
    }
    catch (MyCustomException e)
    {
        return HandleRequestResult.Fail(e);
    }
}

Hope this helps someone.

Upvotes: 4

user433342
user433342

Reputation: 1050

This is what I ended up with:

In startup, after AddOAuth:

.AddScheme<OAuthOptions, BearerAuthHandler>(BearerAuthHandler.DefaultSchemeName, ...);

This goes in your controller:

[Authorize(AuthenticationSchemes = BearerAuthHandler.DefaultSchemeName)]

This is the scheme class: https://dotnetfiddle.net/hujDtz

Upvotes: 0

Related Questions