plantbreeding / BrAPI

Repository for version control of the BrAPI specifications
https://brapi.org
MIT License
57 stars 32 forks source link

Add endpoint for authentication info #552

Open sebastian-raubach opened 2 years ago

sebastian-raubach commented 2 years ago

Currently, it's up to the BrAPI provider to handle authentication, some will use OAuth, others may use username/password login with Bearer tokens or something else entirely. While everyone agrees, that BrAPI should not handle the authentication itself, I think it would be hugely beneficial if BrAPI at least provided information about what authentication mechanism is used along with any necessary information to be able to authenticate using that other service. This would make it possible for client applications to query the BrAPI server and find out what authentication mechanism is used to then authenticate using that information. Whether this is something that could go into /serverinfo or if it should go somewhere else and what exactly the structure of the result should be, I don't know, but I think it's something worth discussing.

BrapiCoordinatorSelby commented 2 years ago

Thanks @sebastian-raubach, Yes I think this would be very beneficial.

I've been hesitant in the past to do something like this because there are many different pieces of info you might need depending on what the exact auth protocol is. For example, when you say username/password, is that through a Basic auth token or credentials posted to an endpoint or some other HTTP header values. For OAuth, I've been encouraging people to use the OIDC Discovery json resource. This is placed in a .well-known/ path and contains all the info needed to support whatever OAuth grant types the server is using. People have suggested we include this discovery file path in /serverinfo to make it very clear that the server supports OAuth and where the details are located.

Bottom line, I think you are right, it would be helpful to add what type of Auth scheme is being used, and perhaps a URL for more details depending on what scheme. But I don't want to get carried away trying to support every possible auth scheme, and neither should you attempt to do that in Flapjack. Choose the auth schemes you can support, and try to get others to conform. I can help with that if you have any uncooperative server teams

BrapiCoordinatorSelby commented 2 years ago

There are more auth schemes available, but off the top of my head, this is what I'm thinking. I bet we could cover 90% of use cases if the server could respond with one of these things

  "authProtocol": "Basic",
  "authProtocolConfigURL": null 
       // A Basic auth token doesn't need any additional params
       // Its base64 encoded username and password sent as a token with every request
  "authProtocol": "OAuth",
  "authProtocolConfigURL": "https://brapi.org/.well-known/openid-configuration"  
       // OIDC Discovery FIle
  "authProtocol": "SAML",
  "authProtocolConfigURL": "https://brapi.org/.well-known/saml-configuration"  
       // whatever the SAML equivalent of OIDC is
  "authProtocol": "Custom",
  "authProtocolConfigURL": "https://not-brapi.org/docs/auth-documentation"  
       // human readable documentation
       // The client either already has all the info it needs for this custom auth protocol for this server,
       // or it doesn't and a dev has to read the documentation to implement it
nahuel-soldevilla commented 2 years ago

I probably should create another ticket with a question, but..

@BrapiCoordinatorSelby, Has the concept of two-factor authentication (2FA), Multi-factor authentication (MFA), etc, ever been discussed or mentioned in BrAPI? (despite auth not being entirely in the scope of BrAPI), or what would be the implications for a BrAPI implementation in a system that also has MFA.

cc @mcrimi @abatac @lik-83 @clarysabel

BrapiCoordinatorSelby commented 2 years ago

@nahuel-soldevilla It has been discussed, but the discussion was short after deciding that BrAPI is not responsible for Authentication. BrAPI has the Authorization standard header which is designed to transport a token with every request. But how that token is produced or consumed is outside of BrAPI scope.

Some groups may choose the "Basic Auth" protocol where the username and password are Base64 encoded into a token. Other groups may decide to use a 2FA/MFA scheme that has user credentials, an RSA key, and a Bio-metric scan. But when the user is done with that whole login process, there should still be a token/JWT that comes out and used for subsequent API requests. BrAPI will work exactly the same for both groups because all it is doing is transporting the token string.

That is one of the reasons why OAuth2/OIDC is so powerful, it hands off control of the login mechanics, and it doesn't care what the user has to do to authenticate as long as you get a token back.

guignonv commented 1 year ago

Since @sebastian-raubach raised the subject today on Slack, it made me think about it again. I'm fine with "externalizing" the authentication process (I do it in my implementation). But the question was "how a BrAPI client application would tell her/his user to login somewhere and then get back the token so the user wouldn't have to do some copy & paste?"

In my case (Drupal implementation), if the BrAPI client behaves like a web browser and support cookies, it can display the Drupal login page and my implementation of the BrAPI server gets the access token (bearer) from both the HTTP header and the Drupal session object (if not found in the header). So, my implementation would work with such a client but it's something too specific. A more generic way would be better. Something like a login URL provided to the client by the /serverinfo call. That URL should be web interface using cookies, so the BrAPI client should also be supporting cookies and it could then use another URL to get the access token. It is something that needs to be think and discussed a little more as there might be some issues with cookies but here's how I would see a first (perfectible) approach:

  1. the BrAPI client calls "/serverinfo".
  2. it got the login URL: "https://myserver.com/brapi/authentication"
  3. it displays that page to the user
  4. the user can submit, fail, retry, got authenticated, etc. In the end, the user just got a web page saying "welcome, you're authenticated"... or something similar ;)
  5. the user can now click on a button on the BrAPI client interface saying that "I'm authenticated"
  6. the BrAPI client now calls "https://myserver.com/brapi/authentication/get-token" and that URL (that will make sure it's from the same user session and not stolen by someone else) will return a JSON with the token
  7. the BrAPI client got the token and can now use it in background for its user

Again, "brainstorming mode". Feel free to propose alternatives or point the approach weakness. ;-)

BrapiCoordinatorSelby commented 1 year ago

@guignonv haha no need for alternatives or points of weakness because you are just re-inventing OAuth hahaha OAuth uses URL parameters instead of cookies, and the "I'm authenticated" button happens automatically, but otherwise you've got it. I'll try to rewrite your example with OAuth.

  1. (optional) The user tells the client application "I'd like to connect to myserver.org"

  2. the BrAPI client application calls myserver.org/brapi/v2/serverinfo

  3. It returns something like this with the OIDC Discovery File

    "authProtocol": "OAuth",
    "authProtocolConfigURL": "https://myserver.org/.well-known/openid-configuration"
  4. The client now knows the server supports OAuth, and has ALL the details it needs in the openid-congfiguration JSON. This includes the login page URL.

  5. The client redirects the user to the login page WITH a callback URL to get back to the the client app and some other metadata. Real example looks something like this

    https://auth.myserver.org/auth? client_id=exampleClient &scope=profile &response_type=token
    &redirect_uri=https://clientapp.org/oauth/redirect
  6. the user can submit, fail, retry, got authenticated, etc. In the end, when the user authenticates successfully, they are automatically redirected back to the client application, following the call back URI redirect_uri. Note here: depending on the OAuth grant type being used ("Authorization Code Grant" or "Implicit Grant") the redirect back to the client app will contain either a one time authorization_code, or jump directly to a user access token

  7. If the client app receives a user access token, then its done (skip to 9.)

  8. If the client app receives an authorization code, then it goes back to the OIDC file for the authorization URL. the authorization code is exchanged for a token.

  9. the BrAPI client got the token and can now use it in background for its user

guignonv commented 1 year ago

:) Yup, I love to reinvent the wheel! :0) No worries, I've already implemented applications using oauth (and even an ancestor) and I definitely know how it works! Thanks. :D Since it seemed too complicated for some clients to use oauth, I tried to propose a different approach but not much simpler, I have to agree ...but it would simplify "my implementation" since it's already there like that. For OAuth, I need to add a Drupal module to the server. Not big deal but an additional dependency.

Anyway, I support the approach you gave above.