0

created an authenticator based on OAuthHandler. in order to make it work, I also needed to specialize a set of options derived from OAuthOptions.

public class MyHandler : OAuthHandler<MyOptions> {
    public MyHandler(IOptionsMonitor<MyOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
        : base(options, logger, encoder, clock) { }

    protected async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens) {
        // accessing OAuthHandler.Options here and everything is initialized.
    }

    public async Task RevokeAuthorizationAsync(string token) {
        // following line throws NullReferenceException on accessing OAuthHandler.Options 
        var request = new HttpRequestMessage(HttpMethod.Post, Options.RevocationEndpoint);
    }
}

public class MyOptions : OAuthOptions {
    public MyOptions() {
        RevocationEndpoint=MyDefaults.RevocationEndpoint;
        // other initialization required here...  
    }

    public string RevocationEndpoint {get;set;}
}

the CreateTicketAsync is a protected method that is overriden from the OAuthHandler base class, whilst RevokeAuthorizationAsync is a speciality of MyHandler.

the login and logout features both work great. since the OAuthHandler doesn't provide any revocation capability, I need to create one to conform with the identity server of the resource being integrated, that is, a cloud-based accounting system.

that being said, I simply thought since the HttpContext within a controller can challenge the authenticator, let's enable it to revoke tokens!

public static class MyHttpContextExtensions {
    public static async Task RevokeAuthorizationAsync(this HttpContext context) {
        var token = context.GetTokenAsync(MyDefaults.AuthenticationScheme, "refresh_token");
        var handler = context.RequestServices.GetRequiredService<MyHandler>();
        // below line calls upon MyHandler speciality method which is to revoke token.
        // for some reason, when the handler is initialized, the Options property doesn't get assigned.
        await handler.RevokeAuthorizationAsync(token);
    }
}

I suspect that I might not initialize the MyHandler the proper way, if it works with the AddMyHandler extension method.

public static class MyHandlerExtensions {
    // many overloads here...
    public static AuthenticationBuilder AddMyHandler(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<MyOptions> configureOptions)
        => builder.AddOauth<MyOptions, MyHandler>(authenticationScheme, displayName, configureOptions);
}

which in turn allows to

public class Program {
    builder.Services
        .AddAuthentication(o => {
            // some config here... 
        })
        .AddCookie()
        .AddMyHandler(o => {
            o.ClientId="my_client_id";
            o.ClientSecret="my_client_secret";
        });
}

so as stated already, login and logout both work fine. but revoke won't because OAuthHandler.Options just won't get initialized/assigned!?

I feel like I must be close, but just can't see it.

Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162

0 Answers0