1

I have a .NET Core web API that uses openiddict for identity management that is tied to ASP.NET identity in a SQL server backend. Many applications can leverage this API with a subscription. I have the following requirements.

  1. Only authorized applications can use the API
  2. Each application can optionally use the identity features of the API to manage their application specific users as implemented by Openiddict within the API (currently the authorization, password, and refresh token flows are enabled).
  3. All endpoints should require that an application be in the Oppenidict application table and this application ID should be available on every request due to multi-tenant support in the API.
  4. Endpoints that have an [Authorize] attribute must be have a user that is authenticated via the Openiddict identity model.

To implement requirement (1), would I need to implement a custom authorization function that checks for an application secret or should another flow be enabled in openiddict that takes care of ensuring only authorized applications are allowed access to the API (regardless of authorize attributes)? In this case, a user may not be authenticated, but the application must still have rights to access the non-authorized endpoints of the API.

To implement requirement (2) for external identity providers, is it possible to configure multiple secrets for each application registered within openiddict to allow their users to leverage facebook or twitter for authentication? This is important, because the API would need call AddFacebook() during configuration for each application that can access the API (not the clientID and secret of the API itself). Because multiple applications each have their own facebookID and secret, I would assume this would only work if openiddict could allow the registration of multiple Ids and secrets for the same provider type via AddFacebook() for example.

To implement requirement (3), is there a built in way to get the application ID of the calling application from openiddict like there is if the user was authenticated?

Geekn
  • 2,650
  • 5
  • 40
  • 80

1 Answers1

0

To implement requirement (1), would I need to implement a custom authorization function that checks for an application secret or should another flow be enabled in openiddict that takes care of ensuring only authorized applications are allowed access to the API (regardless of authorize attributes)?

Starting with RC3, client identification was made mandatory by default: if you don't send a client_id corresponding to an entry in the applications table, your request will be rejected by OpenIddict itself. In previous versions, you could opt for this feature by calling options.RequireClientIdentification() (it's now opt-out).

To implement requirement (2) for external identity providers, is it possible to configure multiple secrets for each application registered within openiddict to allow their users to leverage facebook or twitter for authentication? This is important, because the API would need call AddFacebook() during configuration for each application that can access the API (not the clientID and secret of the API itself). Because multiple applications each have their own facebookID and secret, I would assume this would only work if openiddict could allow the registration of multiple Ids and secrets for the same provider type via AddFacebook() for example.

There's no direct relationship between OpenIddict and the authentication schemes you use, so no, you can't configure multiple Facebook credentials "via" OpenIddict as the two are unrelated.

Assuming you need that for multitenancy purposes, you may want to read https://stackoverflow.com/a/49682427/542757 to learn how you can override ASP.NET Core's default options monitor so you can provide tenant-specific options for authentication handlers like OpenIddict, Facebook, Google and anything else.

To implement requirement (3), is there a built in way to get the application ID of the calling application from openiddict like there is if the user was authenticated?

Assuming it's known (i.e you didn't explicitly make client identification optional in the OpenIddict options), yes. E.g from a MVC controller:

var result = await HttpContext.AuthenticateAsync(OpenIddictValidationDefaults.AuthenticationScheme);
Debug.Assert(result.Ticket != null, "The authentication ticket shouldn't be null.");

// The presenters list contains the authorized parties allowed to
// use the access token with your APIs. Usually, it contains a single value.
// Note: this extension requires a using for AspNet.Security.OpenIdConnect.Extensions.
var client = result.Ticket.GetPresenters().FirstOrDefault();
Kévin Chalet
  • 39,509
  • 7
  • 121
  • 131
  • Thanks for the response. For the first one you provided, I'm not seeing this behavior. I am using RC3, but clientID only seems to be needed when making calls to controller actions that require authentication. It allows methods without the [Authorize] attribute to be called by anyone. My use case is that I need the entire API (both anonymous and authorized actions) locked down to only authorized applications. Once an application has a clientID, they can then access non-authorized actions or require their users to login for authorized calls. You saying that the new feature should do this? – Geekn Sep 23 '18 at 14:52
  • Maybe I wasn't clear enough, but the automatic rejection of requests missing the client_id only impacts token requests (i.e requests you send to get an access token). It's up to you to decorate your own APIs with `[Authorize]` if you don't want unauthenticated clients to reach them. If you want your entire API surface to be protected, use `[Authorize]` everywhere you want to reject anonymous requests. – Kévin Chalet Sep 23 '18 at 16:09
  • In the other words, the typical flow is to make token authentication mandatory for all your APIs and prevent unknown applications from getting an access token. – Kévin Chalet Sep 23 '18 at 16:12
  • Token requests (at least in my thinking) applies to the user that is using an application that leverages the API (not the application itself). There are two identities that are needed (application and optionally the user of the application). I can't wrap my head around how openiddict can support both at the same time via tokens and one "Authorize" attribute. Did the authorize attribute cause the application or user to login? And what happens when an endpoint requires application authentication but not user authentication? – Geekn Sep 24 '18 at 17:35
  • I think the answer to my question is that I will need to ensure that an application is passing an application ID and secret for all requests to the API (regardless of whether or not an endpoint is decorated with an authorize attribute). This will probably have to be done via custom authentication. Once that is done, then "authorize" attributes can be selectively used within the API to force openidict to authenticate the user of the application for those areas that require their identity. – Geekn Sep 24 '18 at 17:35
  • Maybe there is a way to have an authorize attribute on every endpoint with information that says it requires application authentication versus user authentication so it know whether it should authenticate with the client ID and secret or start the normal authentication token flow for a user that wants to login via facebook or something. – Geekn Sep 24 '18 at 17:39
  • When using a user flow like code or password, the 2 identities are known (assuming client identification was required at the token endpoint level) and both are stored in the access token (the claims represent the user and the client id can be retrieved via the presenters list). – Kévin Chalet Sep 24 '18 at 18:09
  • If you have scenarios that don't involve users, consider using the client credentials grant type: it works the same way as the password flow, but the access token represents an application identity (the client acts on its own behalf instead of a user's behalf) – Kévin Chalet Sep 24 '18 at 18:10
  • I think you're last comment hit on it. I need client credential grant type for the entire API and user flow for users on particular endpoints of that API. If the endpoint only requires client credentials (and not user credentials), I'm not sure how it would know which one to use. – Geekn Sep 24 '18 at 18:17
  • You've provided enough time on this one so I'll call it good for now ; ) – Geekn Sep 24 '18 at 18:17