Skip to main content

Command Palette

Search for a command to run...

Third Party Authentication

Updated
6 min readView as Markdown

In the previous blog post, we discussed whether or not you should offer a separate public API. One of the points there was how you do the authentication, and whether that should be done in a separate way. In this blog post, we will go deeper in on that subject and see the different options and which caveats there are.

One of the reasons you would want to offer a separate public API is because of the way authentication works, although that if you use Spring, you can have multiple authentication ways and still use the same API. A different authentication way may also be a good mechanism to make sure other applications don't use your private API, although you can never really prevent this. Whether or not you use the same API, authentication may work differently for a regular user and an application.

For instance, for real users you will work with a JWT token pair (access token and refresh token) which is obtained after the user logs in, and goes through a 2-factor authentication mechanism. The latter is something you do not want for other applications, as they are likely other services without any user intervention. The lack of a 2-factor authentication mechanism means that your credentials have to be more secure, which can be done in a couple of ways, which again depends on what authentication mechanism you use.

A first mechanism is to not have a different mechanism at all. Just let the application do the regular login with a username/password. As mentioned before, this however means that for this user, there can't be any 2-factor authentication configured. Since the application logs in like a regular user, he will get the same tokens as a regular user, all authentication will work out of the box without any extra work, but the application will have to do the same work as a regular user (such as refreshing the tokens). The downside of this approach, is that these credentials can also be used like a regular login. Since the application is an actual user, he will have settings and other data unique to him.

A second mechanism is a simple API token. Such a token can be just a random string of a certain length. The major security risk here is the length of the string. A string that is too short can be brute-forced, but since this is a string that is just copy-pasted in another system once, there is no reason to make this an easy predictable or short string. Generation of the token depends on who it is meant for. If it is meant for another application you manage, you can just agree on a token between the services. If however it is meant for a customer application, it is better that the customer can manage the token, as it becomes essential to be able to revoke the token. This mechanism does require some extra work regarding the authentication mechanism, as you now also need to accept a token header, look it up in your database and use the data there to identify the 'user'.

Another way is to generate a client id / secret pair instead of just a single token. This can then be used to log in, just like a normal user would. You can either generate a JWT token pair, just like for a regular user, or you can generate a single JWT token (either with a longer or shorter validity than for a regular user). The thing is that a user will complain if they have to log in again every 15 minutes, but an application doesn't really care. From an application point of view, refreshing tokens is just as much work as just logging in again. Just like with the single API token, the users should be able to manage the credentials and revoke when no longer needed, or if they fear they may have been compromised. The main advantage of a client id / secret pair is that you decrease the attack vector. By having a pair of generated string it becomes less likely that someone can guess the token, as they now have to guess a matching pair.

Regardless of whether you use the second or third approach, it is important to think about how such credentials are linked. Are they linked to the company/organisation or to a specific user. Maybe you want to have a mix, but be careful with tokens linked to an organisation as this may complicate your application logic. The first thing to keep in mind is whether all data resides on the company/organisation level, in that case there isn't a problem with that approach, but if you have specific settings per user, users can have their own private data or even permissions per user, then the same will impact your token. Does a token always have all permissions? Can it also see data from all the users, creating a way to violate the security on a user level? Another issue arises if you allow modifications on data and you want to offer proper traceability. Changes made by calling the API with an application token are registered as which user? You can't link this directly to an actual users. Both issues can be circumvented by seeing your tokens as some special 'user'. Then you would have a base User concept, of which you have more specific cases TokenUser and LoginUser (but with better names). All information that should be common for both will use the User entity, but you can differentiate between them and add more data to either one of them which is irrelevant for the other.

I am no security expert, but my preferred way would be to use client id / secret pair and issue a JWT token pair. Depending on the use case of the token, I would decide whether or not it should be attached to an actual user or to the company/organisation. For example: it is weird to have automation tasks that are executed by some external system be registered/logged as an actual user. If however the operation would require access to actual user data, the token has to be defined on the user level. No violation of user security can be allowed, even if it is still within the bounds of the same company. The issue of traceability can be solved in the way I mentioned above, and by letting the user give a name to each client id / secret pair.