Search code examples
asp.netasp.net-coreoauth-2.0single-sign-onidentityserver4

OAuth2 protected API. How to allow customer's to SSO using its own authorization server?


I have an Angular Single Page Application (SPA) talking to my ASP.NET API. The API is protected by my own Oauth2 server (IdentityServer4).

One of my customers (let's call him X) wants SSO: Their users on my platform would sign in on their server instead of using the login form in my app that connects to my IdentityServer.

Each customer has its own subdomain for the Angular SPA (e.g. x.myapp.com). Therefore I can easily redirect X's users to their server's authorization page to approve my API, based on the hostname.

However the API itself uses one common hostname for all customers(api.myapp.com). Customers are distinguished by the Origin header of the API call (x.myapp.com) during the login call (and a few other unprotected calls) and by the Bearer token for protected calls to the API.

  1. How does my API introspect the Bearer access token? Who should know which server to query ? Is it the responsibility of the API server? Or can I tell my IdentityServer about X's oauth2 server ?

  2. X's users would also be defined on my platform since we need specific info (such as config of roles on the platform). My current setup implies specific claims (such as user id) that allow my API to know what the user can do. Obviously, X's server will not provide the same claims. How can I connect the dots ? e.g. get some standard claim from X's server (username, email, whatever) and match it to my list of users.

Note: This question is similar but the answer is not accepted and seems to imply that the provider of both identity servers is the same (not the case here).


Solution

  • Formatting my comments as an answer:

    From reading your question it's pretty much clear to me that you could benefit from what is know as Federated identity.

    As you said, one of your customer want to achieve SSO - They want users to login using their existing accounts and be able to user your systems normally.

    Since you already have an IdentityServer in your domain, what you can do is delegate the login part to the customer's side (whatever they do it). This is illustrated in the Identity server documentation Federation Gateway.

    Basically, the approach is that upon hitting the "login" button in your front-end, you would redirect the users to your Identity Server passing some special params (prompt and acr_values for ex) which in turn, tells identity server to redirect the user's to the external Identity provider (the customer's). After a successful login, you have a chance in Identity Server to augment the claims, maybe using something they returned or anything really. Then the process is as normal - you return a JWT Token generated by your Identity Server

    The benefit of doing this is:

    • Your SPA/API doesn't have to change. You will still work with your own bearer tokens and can continue doing authN/AuthZ as before.
    • You have a chance to add claims that might indicate where this user is coming from if needed
    • If your customer's server changes, you don't have to worry much, apart from maybe some tweaks related to returned claims
    • They don't necessarily need to use OpenId/OAuth on their side for this to work

    Useful things you probably will need is some params to pass during the call to the authorize endpoint in Identity Server. (acr_values and prompt).

    You can also check this in the quickstarts, by looking at Sign-in with external providers (which is pretty similar to what you want)

    Now to your individual points:

    1. Your Identity Server should be the "bridge" between you and the customer's "identity provider".

    2. Upon a login from an external provider (X), you need to somehow identify the user on your platform. You could use email or, even better, if X is already using OpenId/OAuth they might give you the sub claim which is the user id on their side. At this point you need some sort of agreement with them otherwise this might be flaky/unreliable for both sides.

    In a more "advanced note" you could also add to your tokens some sort of claim that tells you who is the source provider of this user. Here the source provider would be X. This is useful because you might want, for example, configure allowed identity providers in your app, or maybe enable features only for certain providers. Like, ppl logging in with Google might only see certain parts of the app.