I have finally time to work on this. But before i start I would like to clarify my point of view.
Lets start with authorization.
Authorization
Right now Squidex uses OpenId Connect. It is a well established standard and a proven implementation. We use it together with a client.
Clients
A client in OpenId Connect represents another application, that wants access. For example an mobile app, server application, website or Desktop application. A client can has several modes, called Grant Types.
-
Implicit: When a user goes to a login page, gets a token and so on. Only works with Users, that are registered in the OpenId Connect implementation. This is the default for every user in Squidex.
-
ClientCredentials: An application can get a token without a user, using the client id and secret.
When you create a new client for an app, this client is made available to the OpenID Connect implementation. It is not stored in the database, but an interface is implemented to support that.
This does not mean that it is the only option to have clients .The frontend is also a client for example and we could also create one client for each “end-user”.
Except clients there is another way to implement authorization:
API Keys
With API keys you share the key directly with each request. Therefore it is less secure. But for a Javascript frontend application where you have to make the client id and secret publicly available it does not really matter.
JWT Tokens
When you implement API Key authorization you have to check for each request if the API key is valid. You can solve this problem with JWT tokens (https://jwt.io/introduction), which are signed API keys.
The API key contains all information such as username and you can also store permissions there and with each request you only verify the signature of the JTW token.
Users
For me a user has several aspects and very often a user exists in more than one place.
-
Profile For example you wanna customize which profile information you collect.
-
Authorization to Squidex As described above there are several methods to manage that, e.g. clients, API keys and self contained API keys.
-
Authorization to a custom Frontend: For example when you want to store username and password somehow.
When we talk about the implementation, we have to think about what is the most easiest way in terms of implementation and new added features and what is the most easiest way for users and developers. We can implement something now that is a little bit tricky to use and then improve it later.
Suggestion
This is my suggestion:
- The Profile part is the hardest part to implement, but we already have that with schemas. It makes no sense to implement another dynamic content type in my opinion. Therefore I would leverage schemas for that.
- The Authorization to a custom Frontend is already possible and you can use scripting to hash the password.
- For Authorization to Squidex we have to store the API keys or clients somewhere. The current client structure is not sufficient because it is directly part of the app config, which is a single document (row) in the database. So you cannot have 10.000 clients. Therefore we need to create another structure for API keys or clients.
- When you create a user schema you wanna connect an API key to each user. You can also do this with scripting when point 3 is implemented. Not the best approach but it would work.
So how does it look like?
If we have implemented the client or API key list (point 3), we can write a very simple script:
// Create
if (ctx.data.password.iv) {
ctx.data.password.iv = sha256(ctx.data.password.iv);
}
createAPIKey(function (result) {
ctx.data.apiKey.iv = result;
});
replace();
// Delete
deleteApiKey(ctx.data.apiKey.iv);
Improvements
How can we improve that?
- Build a structure to cleanup fields for deleted contents.
- Write a custom field that provides an API key automatically.
- Provide an inbuilt way to hash fields without scripting.
Open questions
- How do you want to connect to Squidex? Clients vs APIKeys. Clients are more secure but APIKeys are easier to use.