OA-24 - Should we allow to create the caller on the fly?

@achachiez @ibacher @mksrom @wyclif one of the many questions around OA-24 is: should we allow for an option to create the caller on the fly?

Recap: OA-24 covers the work to support JWT-based authentication for service accounts. (Eg. dbsync could be such a service account needing to make API calls to OpenMRS. When doing so it attaches a signed JWT to its HTTP requests.)

When OpenMRS successfully decodes JWTs, it is then able to read the identity of the caller in it. In a nutshell the caller is the OpenMRS user that should be impersonated as being the sender of the HTTP request. When the identity (say the username) of the caller is read out of the JWT, there’s two possibilities:

  • Either the username points to an existing user. Then all is fine, let’s impersonate that user.
  • Or the username does not point to any existing user.

My question is about the latter case, should we always fail? Or should we create that user on the fly, possibly as a system admin? If we decide to allow this it will certainly be the non-default strategy out of those two: 1) “fail if caller does not exist” and 2) “create a sys admin caller on the fly”.

Any thoughts on this? For those feeling some reluctancy to create users on the fly, note that the module already does that with regular authenticated users (as in non service accounts), see here.

So, my gut feeling is that creating ordinary users on the fly from an appropriate authentication source is appropriate; however, creating system administrators is not something that should be done on the fly. Since this ticket is aimed at service accounts, ensuring an appropriate service account exists in OpenMRS before allowing it to do anything seems like an appropriate burden.

So, I would go for 1, “fail if the caller does not exist”.

My super-paranoid recommendation would be to just drop the request without a response at all (on the grounds that any response could potentially provide potential hackers with useful information), but that’s probably overkill and feedback is good for the usual case where something just isn’t configured properly.

I agree with @ibacher that we should not auto create user accounts for service accounts, these services are always ‘known’, it’s a fair assumption to expect that the admin created a user account for a service before onboarding it with predefined roles.

Thanks both, looks like we’ve got a plan.

Definitely do not create users on the fly. A JWT token for a non-existent user is a very bad sign, since the server is supposed to have signed the token in the first place.

Ideally, you would not only ignore the request, but also invalidate the token… but, that’s a downside of JWT tokens… you can’t revoke them. Hopefully, all JWT tokens have a fairly short expiration (minutes) to limit damage. If we need tokens for longer, then we should be creating app tokens that can be revoked (not JWT tokens).

@burke I agree that if OpenMRS cannot verify a token then it should invalidate it (and that cannot be done, which leaves us with setting the TTL appropriately.)

My question was only for the case of encrypted and signed tokens that can be verified.


Also there’s scenarios where we do not have the control on the caller ID value that the token will embed in its payload. For instance, @achachiez/@wyclif to confirm, apparently Keycloak seems to generate that caller ID once and for all at the creation of the client. So rather than going through the extra process of creating the user that corresponds to that Keycloak-generated caller ID in OpenMRS, I was wondering if the OAuth 2 Login module could not allow for an option to do that at first validation of a token that references the caller ID.

I think I got my answer :slightly_smiling_face:

Obviously this is all extra work and head scratches because OpenMRS does not fully implement Spring Security and requires to manage users even when authentication and authorisation are delegated to an IdP.

FYI the oauth2login module assumes base64 encoded non-encrypted tokens.

Sorry, I thought you had a situation where the server was signing JWT tokens for usernames and then received a JWT token with a non-existent username (which presumably couldn’t/shouldn’t have been created in the first place).

In your use case, wouldn’t the check for the foobar user (and potentially creating a foobar user on the fly under Keycloak’s authority) happen at the time the JWT token was being initially signed?

<aside> Ideally, no account should be able to impersonate an account with elevated privileges (i.e., a service without superuser privileges should not be able to impersonate an account with superuser privileges). </aside>

For the foobar user to be created on the fly it would have to authenticate, as in normally as any user would do. We would have to see if the emission of the JWT does provoke such authentication by any chance. I don’t know but I don’t think so, @achachiez?


For the foobar user to be created on the fly it would have to authenticate, as in normally as any user would do. We would have to see if the emission of the JWT does provoke such authentication by any chance. I don’t know but I don’t think so, @achachiez?

Does this pertain to the the privileges of the users from Keycloak?

Sorry @achachiez, I was sort of dreaming out loud (and being unclear).

We have a mechanism to create users on the fly: it’s when they access an OpenMRS URL for the first time, get redirected to the IdP, get authenticated with the IdP, and get back - authenticated - to OpenMRS.
… and I was naively hoping that we can leverage this, somehow, with service accounts at the moment of issuance of the JWT.