V6 Authorization and API changes afoot

Thanks for the coding/review help and especially keeping up with the darn official documenting @brady.miller.

@Amiel You folks are probably the furthest along with implementing this feature. Just wanted you to be aware that Brady and I have tightened security and updated the feature and is in master now.

I am very curious how you plan to use the feature. Are you primarily going to use with password grant or how do you plan to use the password grant?

Are you still looking into hooking in a third party provider or MFA?
Do you plan to use the public application type for your users and thus the code challenge flow?
Besides the implemented custom scopes of api:fhir, api:oemr, api:port and api:pofh are there others i’ve missed?

Feedback by anyone is appreciated before I move on to adding a SMART layer which i’ll probably start a new thread to track. SMART will not be included in our upcoming initial release of v6.0.0 but will soon follow.

Hi @sjpadgett
Thank you for being interested in us.
We are actually at the end of the development of a client-side application based on React for Emergency medical centers, the application needs to start a pilot in the next weeks therefore for now we implement Grant password authentication that matches to existing code, I hope we continue to Code grant when the project will grow up.
For MFA (we must for security requirements) we plan to expand the existing MFA found in the login of openemr to grant password in the API (for users that turn the MFA on), hopefully to create pull request soon.

Our application use a openemr API and FHIR api but most of the calls address to our zend modules that expand the api.

On this occasion I invite you to take a look on our projects, all the source is open, and from the last weekend integrated with the latest Openemr code.

backend modules -



React client -

devops tools -

Always happy about collaboration.

Best regards
Amiel

1 Like

@sjpadgett @brady.miller
Just the last issue is missing in the new authorization server - logout action. would Do you plan to write it soon?
Thanks a lot…

Thanks @Amiel for sharing what your team has been up to. Very exciting work of which exposure on this thread may help some other community members. I know I learn a couple things.

Concerning logout action, yes I hope to have a PR up tonight or tomorrow that will include logout, revoke and maybe finalize the userinfo endpoint.

I’m still a little concerned with registration and may add a few items to track.

As for MFA, I assume our current core solution meets your need although, it sure would be handy to have in authorization server for apis.

Edit: Looking at a logout, i’m somewhat undecided how best to handle in our implementation.
I don’t issue cookies to user agent/user to maintain a persistent session state. I persist in a table.
As far as server is concerned, you are signed into the server unless a refresh token has expired at which point client must sign back into server to get a new token.
So a logout for us would really just be a revoke of refresh token.

How do you see this working?

For client logout here is pattern i’m thinking. Please, anyone with further input, please chime in.

  • basic
GET https://{baseUrl}/logout?id_token_hint=${id_token}

The trusted user session associated/identified by the id token will be deleted and a confirmation displayed.

  • registered redirects request initiates a logout and redirects to the post_logout_redirect_uri. The registered post_logout_redirect_uri and the request post_logout_redirect_uri must match.
GET https://{baseUrl}/logout?
  id_token_hint=${id_token}&
  post_logout_redirect_uri=${post_logout_redirect_uri}&
  state=${state}

Both initiate a redirect to either the OP confirm dialog or the redirected endpoint depending on request.

HTTP 302 Found
Location: https://post_logout_redirect_uri/redirect&state=${state}
2 Likes

If post_logout_redirect_uris is provided during registration then after session is destroyed, server will redirect to that endpoint otherwise, a logged out message is sent to user logging out.

We maintain user sessions as trusted users where a log out is essentially removing the trusted user resulting in resource server dispatch denying any tokens, valid or not, from advancing api request until user logs back into identity server.

I don’t see any reason to revoke tokens because that would essentially just be invalidating current session the tokens were issue against. If disagreement, please comment.

@Amiel this probably is of interest you.

1 Like

Looks excellent. thank you!

Announcing the token introspection endpoint and if I may say, at one point I just wanted to have a response of yep or nope. I mean, why be so formal!:slight_smile:

  • Only access_token and refresh_tokens will be validated. I may add id_token later but, it is really not needed IMO.

  • All Http status responses will be 200 with response showing whether active and the token status. Exceptions are in the case token fails signature verification or a mangled request then you’ll see appropriate 400/401/500.

  • To fetch url from discovery json use 'introspection_endpoint' that yields something like https://localhost/oauth2/default/introspect

  • Request attributes:

Field Description Type Required
client_id Application client Id String Yes
client_secret Application Client Secret. If client has private(confidential) registration status, then a client secret is mandatory otherwise, public apps only require client_id. String Yes
token_type_hint The appropriate token hint of access_token or refresh_token String Yes
token The string value of the token returned from auth token endpoints. String Yes
curl -X POST -k -H 'Content-Type: application/x-www-form-urlencoded'
 -i  'https://localhost:port/oauth2/default/introspect' 
--data 'client_id=kbyuFDidLLm280LIwVFiazOqj...
&client_secret=khYVHgkbBBYUU...
&token_type_hint=refresh_token
&token=def50200695611d39349fad4bb913b686e1c53fc99116ebabdfcc08...
  • Responses:

Active Token

Response Body Field Value Returned
active true
status ‘active’
exp Expiry Epoch Time
sub The subject of the token. Mostly user_id UUID
scope Token scopes
client_id Application Client ID Value

Expired Token

Response Body Field Value Returned
active false
status ‘expired’
exp Expiry Epoch Time
sub The subject of the token. Mostly user_id UUID
scope Token scopes
client_id Application Client ID Value

Revoked/Logged out User Token

Response Body Field Value Returned
active false
status ‘revoked’
exp Expiry Epoch Time
sub The subject of the token. Mostly user_id UUID
scope Token scopes
client_id Application Client ID Value

Invalid Client Id or Client Secret
Also case of token client info doesn’t match trusted user. In both regards let’s not return anything useful

Response Body Field Value Returned
active false
status ‘invalid’
  • A refresh_token example response
{
    "active": true,
    "status": "active",
    "scope": "openid email phone api:fhir api:pofh site:default",
    "client_id": "kbyuFDidLLm280LIwVFiazOqjO3ty8KH",
    "exp": 1614792378,
    "sub": "91e65743-aa8c-4a7e-a183-706912c92436"
}
  • A token invalid client example response
{"active":false}

So I think this gives a good overview of this endpoint. Comments welcomed.

Temporary note: I got a jump start on documenting this for comments with the PR going up within a day and in master shortly thereafter. I’ll post back once in master.

1 Like

Hi I’m trying to test out the new API, I see that it requires SSL.

I looked on the instructions and it said to set the baseurl at Administration->Globals->Connectors->'Site Address

Did the Site Address field move? I don’t see it in connectors, there’s an eRX site address but I don’t think that’s it.

Hi @RachelEllison
Hope you’re using v6.0.0-dev because this is not a v5.0.2 feature. However,

also I don’t check for a SSL certificate, yet, but, soon. Still, hit endpoints as https://…

Hi Jerry,

I am on version 6.0.0-dev

The site address textbox is missing in my connectors settings.

I tried pasting the the example on the readme without any changes and got the below error.

When is the last time u updated your dev version with master as this was added just recently?

I believe about 3 weeks ago. The curl queries I had used previously no longer work so I assume it’s due to the API changes.

That’s because we removed the old auth method and add new which is different endpoints.
Your request look okay.
Pull in current master and rebuild. Then try to register after setting up globals.

I’ll throw out there for other’s benefits who are trying to follow along with the CURL requests on the api documentation that I had to urlencode my curl request to get things to work. I’m on ubuntu w/ bash on the command line so not sure if its different on other environments as any spaces, colons, or slashes were creating errors.

Note you use the client_id you get from the registration request Jerry mentions. The state parameter is a randomly generated string you will use as a CSRF token. It will get returned to you at the callback URL you provided in the redirect_uris as part of your application client registration call and you can use it to make sure the request hasn’t been tampered with.

curl -X GET -k -i ‘https://localhost:9300/oauth2/default/authorize?response_type=code&client_id=9qAEZoCDYOdDlCeU1oJbNo-uItuzKxEqBCLz9hq6McA&state=a85b870548dd8880ddb7c3192439f468fe63396f&scope=openid%20email%20phone%20address%20api%3Afhir

(Note I’m using the default OpenEMR easy development docker install here).

1 Like

So another thing I’ve been running into problems and figured out that outside of the initial registration request any use of the redirect_uri parameter that @sjpadgett uses in his examples would return invalid responses. I haven’t dug into the code yet as to figure out why that is, but if you only use the redirect_uri parameter in the initial registration request, I was able to get things to work from start to finish.

Note the code parameter returned from the authorization request https://localhost:9300/oauth2/default/authorize (after you provide username/password and authorize the scopes) is VERY shortlived (I think its set to 60 seconds) so if you are manually testing this on the CLI you’ll want to make sure to handle that final request to https://localhost:9300/oauth2/default/token to get your access token is done quickly.

Any client request that includes the redirect_url must match the registered redirect_url. This is a security feature of the spec.

Should be 10 minutes. I had it at I think 1 or 2 minutes at one time but changed it I thought!

nope, production is set at 1 minute. Not sure I want to change longer.

yep, reminds when I was trying to use cli for code flow (quickly copy/pasting things :slight_smile: ). For code flow testing and development I now use a simple oauth client (@sjpadgett pointed me towards it in the past) which make working on code flow development much easier. The package is here:
GitHub - jumbojett/OpenID-Connect-PHP: Minimalist OpenID Connect client

And I have 2 client.php setups.

easy dev environment: https://gist.github.com/bradymiller/82202f0c1157f57e58cd7f8967766ade

online demo testing: https://gist.github.com/bradymiller/1d3f06b3c8a2c420204f5ed28d2bd3d6

You basically populate the client id and secret in the client.php script and then point your web browser to it and presto (the code is really simple too, so was a way for me to learn how the heck all this stuff including state/nonce were working). I installed it on my local environment outside the dockers.

Hi Jerry,

I pulled the latest version and rebuilt. Is this the correct site address for testing?

I tried the example in the readme and got the below. Does that look right?

Nope, looks to me like the dependencies were not updated.
Did you rebuild after source update?