thephpleague / oauth2-server

A spec compliant, secure by default PHP OAuth 2.0 Server
https://oauth2.thephpleague.com
MIT License
6.52k stars 1.12k forks source link

Validating access tokens from multiple authorization servers #1201

Closed garethellis36 closed 3 years ago

garethellis36 commented 3 years ago

Hello,

I'm working on a project where we will have an application in a public, web-facing server, talking to a PHP API on a server in an enterprise LAN.

The application will need to support two login types: one type of user comes from our own company, and will authenticate with our enterprise Active Directory; the other type of user comes from outside, and will authenticate using username and password stored in the database for the PHP API on the LAN.

The simplest flow for the internal users will be for us to set-up OAuth2 with ADFS, that is, the user is redirected to ADFS itself for an auth code, then our public application uses the code to get an access token from ADFS. I'm assuming that as long as our PHP API has the public key from ADFS, it will be able to validate that access token.

For external users, we will need to use password grant to get an access token from our PHP API (i.e. using a different private/public key pair).

Given this, there is the possibility that our public application could make an API request with an access token which has come from a couple of different places -is there any way to wire up this library so that we can make determination of which public key to use to validate the token (the one from our PHP API server vs the one from ADFS)? The only thing I can see so far would be a workaround using try/catch and making multiple attempts to validate the token.

If not, is there an alternative flow we could use? The only one I can think of is to use SAML to authenticate the user in the public application, and then just use client credentials grant to get an access token, but this would require some additional mechanism for identifying the actual user to the API, which feels like a bit of a fudge.

Thanks for your advice, and thanks for the library - it's been very easy to use so far.

eugene-borovov commented 3 years ago

You can use iss claim to determine auth server.

garethellis36 commented 3 years ago

I've decrypted a token created by this library and it does not contain an iss claim. Is there a way to configure this library to include that claim in the JWT? And if so, I don't see a way to directly inspect the claims on the token, because the entry point for validating the token is a PSR-7 middleware that just adds access token ID, client ID, user ID, and scopes to the response attributes. Would I need to implement my own AuthorizationValidatorInterface?

eugene-borovov commented 3 years ago

Does ADFS token contain an iss claim token? You really need to implement the AuthorizationValidatorInterface to add issuer analysis. This library lacks the ability to configure the iss claim.

garethellis36 commented 3 years ago

I don't know that yet, I haven't talked to our AD team to see if we can even configure our version of AD to use OAuth. I'm theorizing/planning at this point. Thanks for your help!

Sephster commented 3 years ago

You would need the iss claim from the JWT and as @eugene-borovov said, we don't support this at the moment. I did try to code something up to support this this morning but it would be a breaking change so won't come in until we release a major version which would be some time away.

I also would recommend you do not use the password grant any more as it is deprecated. You should be able to just use the auth code grant with PKCE.

Sephster commented 3 years ago

Just thinking on this more though, the iss claim is really just so the recipient of the token can confirm it came from where they expected it to.

I think you'd be better, if possible, to just have a single auth page with maybe a checkbox saying you are an internal or external user (or whatever makes most sense), and depending on this, it fires the form to validate against either the DB or the AD server.

That would mean you don't have to maintain two different key pairs.

garethellis36 commented 3 years ago

I think we could in theory inspect the JWT in a separate middleware before using this lib's middleware to validate the token - we could (again, in theory) see if the JWT has an iss claim, check it's value, and wire up the appropriate public key for the next middleware to use. Google is telling me that ADFS-issued JWTs include an iss claim. But it doesn't feel right, and as you say, it sounds like a misuse of the iss claim too.

In an ideal world, we could configure users from any external company for federated SSO through our ADFS instance, then we could just get access tokens from ADFS alone. However, I think it's likely that for some of our smaller customers we would need to support some other method of authentication.

I also would recommend you do not use the password grant any more as it is deprecated. You should be able to just use the auth code grant with PKCE.

An auth code grant requires an "authorization server" to redirect to though, right? So if the user is from an outside company where we can't support integrated SSO, what is the authorization server? I don't think we have one. We have:

The two public-facing components can talk to each other, and the customer-facing app can call the API of the legacy app, but can't talk to the database. The legacy app is the only thing allowed to talk to the database.

I guess I need to start this week by talking to our AD team to see what their take is, what their experience of AD support in smaller clients is, etc.

Sephster commented 3 years ago

Yep, you will need to have an authorization server but you'd need to have that for using the password grant too as you need to authenticate the user's username and password somewhere.

I think this question is probably outside the scope of the support channels for this package as it sounds more like an architectural discussion you need to have with your colleagues.

In most situations with OAuth, you have a protected resource that you own, and you want to share it with an outside party without sharing your credentials e.g. your Facebook posts/photos.

It sounds like your database is your protected resource in this situation but you have two possible ways to authenticate which complicates matters. I can't get enough of a full picture of your scenario but my strong advice would be to work towards getting a single login gateway to simplify things if your external and internal users are accessing the same resource. How this is authenticated in the backend can be obfuscated from the user.

Sephster commented 3 years ago

Closing this due to lack of activity. Please feel free to reply if you have further questions/comments.