Permissions
Before continuing, your app needs to have profiles sorted out. In other words, if it needs to work with a completely new type of events, it first needs to notify the system of that new type of event. If the app just wants to process some existing events, you already should know, you don't need to do anything.
Requesting New Permission (application part)
When you app wants to access raw events, it needs to specify which profile it wants to access and what rights the app wants. Events are bound to profiles so that's the reason why profile name must be specified in every event.
When the app requests to access a profile ( we mean a set of events having that particular profile in the metadata) which does not exist, this is totally fine and the app will get an empty list of events. The idea is that in future, such profile may be created, rendering the set of events of that particular type non-empty.
The app needs to hit this endpoint: /app/api/requestNewPermission (POST) with the following body (as example):
{
"jwtTokenForPermissionRequestsAndProfiles": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBJZCI6IjY1ZmFlMDk0N2E5MGI0YTUyNjNhNDk4MCIsIm5hbWVEZWZpbmVkQnlVc2VyIjoiTXkgTmV3IEFwcGxpY2F0aW9uIiwibmFtZURlZmluZWRCeUFwcCI6ImFwcGxpY2F0aW9uLmNvbSIsImlhdCI6MTcxMDk0MDcxMywiZXhwIjoxMTE3ODIyMDcxM30.3zHTC0_igQKfzjF8uZadJLkmd4qRXY_hePd_M6pmPj0",
"permissionsRequest": {
"profile": "application.com/first_profile",
"read": true,
"create": true,
"modify": true,
"delete": true
},
"optionalMessage": "This is optional message for the permission from the app"
}
Optional message can be left out. This is just an opportunity for the app to state its reason behind this permission request. This message is shown in the admin frontend Control Centre component.
There are multiple possible responses:
- everything ok,
generatedAccessTokenis returned.
{
"message": "Permissions requested successfully",
"generatedAccessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhQWNjZXNzUGVybWlzc2lvbklkIjoiNjVmYWZiM2UxYjI3YjQxNjE0NTk0Mjc3IiwiYXBwSWQiOiI2NWZhZTA5NDdhOTBiNGE1MjYzYTQ5ODAiLCJwZXJtaXNzaW9uIjp7InByb2ZpbGUiOiJhcHBsaWNhdGlvbi5jb20vZmlyc3RfcHJvZmlsZSIsInJlYWQiOnRydWUsImNyZWF0ZSI6dHJ1ZSwibW9kaWZ5Ijp0cnVlLCJkZWxldGUiOnRydWV9LCJjcmVhdGVkRGF0ZSI6IjIwMjQtMDMtMjBUMTU6MDU6MzQuNDE3WiIsImFwcHJvdmVkRGF0ZSI6bnVsbCwiZXhwaXJhdGlvbkRhdGUiOm51bGwsImlhdCI6MTcxMDk0NzEzNCwiZXhwIjoxMTE3ODIyNzEzNH0.30tA0SPYMcYMdVg15Mqll6bcFOnE41u9rRGcF5kIY5M"
}
Just as with jwtTokenForPermissionRequestsAndProfiles, your app needs to remember generatedAccessToken which will be used once the app decides to manipulate or processs events in some way.
- invalid
jwtTokenForPermissionRequestsAndProfiles
{
"message": "Invalid or expired JWT token"
}
Remeber, this was just a permission request which needs to be approved. Unless it's approved, the app cannot do anything about it. However, the app has an option to check for permission status (access token status) and so can notify its user that they should take an action if they want to fully use their new app. Or maybe the user will find out the app wants to access some other irrelevant data it should have no access to!
Checking Permission Status
To check the permission status, there is this endpoint /app/api/checkAccessTokenStatus?accessToken=[token] (GET).
So for the result above, the request looks like this:
[AUTH SERVICE URL]/app/api/checkAccessTokenStatus?accessToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhQWNjZXNzUGVybWlzc2lvbklkIjoiNjVmYWZiM2UxYjI3YjQxNjE0NTk0Mjc3IiwiYXBwSWQiOiI2NWZhZTA5NDdhOTBiNGE1MjYzYTQ5ODAiLCJwZXJtaXNzaW9uIjp7InByb2ZpbGUiOiJhcHBsaWNhdGlvbi5jb20vZmlyc3RfcHJvZmlsZSIsInJlYWQiOnRydWUsImNyZWF0ZSI6dHJ1ZSwibW9kaWZ5Ijp0cnVlLCJkZWxldGUiOnRydWV9LCJjcmVhdGVkRGF0ZSI6IjIwMjQtMDMtMjBUMTU6MDU6MzQuNDE3WiIsImFwcHJvdmVkRGF0ZSI6bnVsbCwiZXhwaXJhdGlvbkRhdGUiOm51bGwsImlhdCI6MTcxMDk0NzEzNCwiZXhwIjoxMTE3ODIyNzEzNH0.30tA0SPYMcYMdVg15Mqll6bcFOnE41u9rRGcF5kIY5M
And the response is following:
{
"isActive": true,
"isRevoked": false
}
So if the access token is not active, your app can notify user that they need to approve this permission.
Getting Unapproved Permissions Requests (admin part)
For getting a full list of unapproved permissions, admin can hit this endpoint (it is paginated): /admin/api/permissions/getUnapprovedPermissionsRequests?pageIndex=2&limit=100 (GET)
The response is the following:
{
"status": "success",
"data": {
"permissions": [
{
"_id": "65faf9c8f9b73ae41344361f",
"app": {
"_id": "65f85d8f72d3cb5a148a96f6",
"nameDefinedByUser": "My New App",
"dateOfAssociationByApp": "2024-03-18T15:28:29.331Z",
"jwtTokenForPermissionRequestsAndProfiles": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBJZCI6IjY1Zjg1ZDhmNzJkM2NiNWExNDhhOTZmNiIsIm5hbWVEZWZpbmVkQnlVc2VyIjoiTXkgTmV3IEFwcCIsIm5hbWVEZWZpbmVkQnlBcHAiOiJhaG9qLmNvbSIsImlhdCI6MTcxMDc3NTcwOSwiZXhwIjoxMTE3ODA1NTcwOX0.EKgX4SevCgdCUq3QbpWbSahb47sbJL9o9hGGtfQIY10",
"dateOfRegistration": "2024-03-18T15:28:15.541Z",
"__v": 0,
"nameDefinedByApp": "ahoj.com"
},
"optionalMessage": "This is optional message for the permission from the app",
"permission": {
"profile": "ahoj.com/first_profile",
"read": true,
"create": true,
"modify": true,
"delete": true,
"_id": "65faf9c8f9b73ae413443620"
},
"createdDate": "2024-03-20T14:59:20.695Z",
"approvedDate": null,
"isActive": false,
"revokedDate": null,
"expirationDate": null,
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhQWNjZXNzUGVybWlzc2lvbklkIjoiNjVmYWY5YzhmOWI3M2FlNDEzNDQzNjFmIiwiYXBwSWQiOiI2NWY4NWQ4ZjcyZDNjYjVhMTQ4YTk2ZjYiLCJwZXJtaXNzaW9uIjp7InByb2ZpbGUiOiJhaG9qLmNvbS9maXJzdF9wcm9maWxlIiwicmVhZCI6dHJ1ZSwiY3JlYXRlIjp0cnVlLCJtb2RpZnkiOnRydWUsImRlbGV0ZSI6dHJ1ZX0sImNyZWF0ZWREYXRlIjoiMjAyNC0wMy0yMFQxNDo1OToyMC42OTVaIiwiYXBwcm92ZWREYXRlIjpudWxsLCJleHBpcmF0aW9uRGF0ZSI6bnVsbCwiaWF0IjoxNzEwOTQ2NzYwLCJleHAiOjExMTc4MjI2NzYwfQ.yHg2A8plYpxhusRTqTFXwmhNj3sz0722mB5pRJCKyqY",
"__v": 0
},
{
"_id": "65fafb2f1b27b4161459426f",
"app": {
"_id": "65f85d8f72d3cb5a148a96f6",
"nameDefinedByUser": "My New App",
"dateOfAssociationByApp": "2024-03-18T15:28:29.331Z",
"jwtTokenForPermissionRequestsAndProfiles": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBJZCI6IjY1Zjg1ZDhmNzJkM2NiNWExNDhhOTZmNiIsIm5hbWVEZWZpbmVkQnlVc2VyIjoiTXkgTmV3IEFwcCIsIm5hbWVEZWZpbmVkQnlBcHAiOiJhaG9qLmNvbSIsImlhdCI6MTcxMDc3NTcwOSwiZXhwIjoxMTE3ODA1NTcwOX0.EKgX4SevCgdCUq3QbpWbSahb47sbJL9o9hGGtfQIY10",
"dateOfRegistration": "2024-03-18T15:28:15.541Z",
"__v": 0,
"nameDefinedByApp": "ahoj.com"
},
"optionalMessage": "This is optional message for the permission from the app",
"permission": {
"profile": "application.com/first_profile",
"read": true,
"create": true,
"modify": true,
"delete": true,
"_id": "65fafb2f1b27b41614594270"
},
"createdDate": "2024-03-20T15:05:19.114Z",
"approvedDate": null,
"isActive": false,
"revokedDate": null,
"expirationDate": null,
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhQWNjZXNzUGVybWlzc2lvbklkIjoiNjVmYWZiMmYxYjI3YjQxNjE0NTk0MjZmIiwiYXBwSWQiOiI2NWY4NWQ4ZjcyZDNjYjVhMTQ4YTk2ZjYiLCJwZXJtaXNzaW9uIjp7InByb2ZpbGUiOiJhcHBsaWNhdGlvbi5jb20vZmlyc3RfcHJvZmlsZSIsInJlYWQiOnRydWUsImNyZWF0ZSI6dHJ1ZSwibW9kaWZ5Ijp0cnVlLCJkZWxldGUiOnRydWV9LCJjcmVhdGVkRGF0ZSI6IjIwMjQtMDMtMjBUMTU6MDU6MTkuMTE0WiIsImFwcHJvdmVkRGF0ZSI6bnVsbCwiZXhwaXJhdGlvbkRhdGUiOm51bGwsImlhdCI6MTcxMDk0NzExOSwiZXhwIjoxMTE3ODIyNzExOX0.xKHy4xRcK-Kwysesp9wh7YdgBucAvrJgRiuZDW9QoHY",
"__v": 0
}
],
"totalItems": 2,
"totalPages": 1,
"currentPage": 0
}
}
This endpoint, as mentioned before, is utilised by the Control Centre.
Getting Unapproved Permissions Requests For Given App (admin part)
For getting a full list of unapproved permissions for a given app, admin can hit this endpoint (it is paginated): /admin/api/permissions/getUnapprovedPermissionsRequests/:appHolderId (GET)
appHolderId is the id you get when you register a new app holder (look here).
For this request /admin/api/permissions/getUnapprovedPermissionsRequests/65f85d8f72d3cb5a148a96f6 the following is the response:
{
"status": "success",
"permissions": [
{
"_id": "65f85e6e72d3cb5a148a971f",
"app": {
"_id": "65f85d8f72d3cb5a148a96f6",
"nameDefinedByUser": "My New App",
"dateOfAssociationByApp": "2024-03-18T15:28:29.331Z",
"jwtTokenForPermissionRequestsAndProfiles": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBJZCI6IjY1Zjg1ZDhmNzJkM2NiNWExNDhhOTZmNiIsIm5hbWVEZWZpbmVkQnlVc2VyIjoiTXkgTmV3IEFwcCIsIm5hbWVEZWZpbmVkQnlBcHAiOiJhaG9qLmNvbSIsImlhdCI6MTcxMDc3NTcwOSwiZXhwIjoxMTE3ODA1NTcwOX0.EKgX4SevCgdCUq3QbpWbSahb47sbJL9o9hGGtfQIY10",
"dateOfRegistration": "2024-03-18T15:28:15.541Z",
"__v": 0,
"nameDefinedByApp": "ahoj.com"
},
"permission": {
"profile": "ahoj.com/first_profile",
"read": true,
"create": true,
"modify": true,
"delete": true,
"_id": "65f85e6e72d3cb5a148a9720"
},
"createdDate": "2024-03-18T15:31:58.115Z",
"approvedDate": "2024-03-18T15:32:24.954Z",
"isActive": true,
"revokedDate": null,
"expirationDate": null,
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhQWNjZXNzUGVybWlzc2lvbklkIjoiNjVmODVlNmU3MmQzY2I1YTE0OGE5NzFmIiwiYXBwSWQiOiI2NWY4NWQ4ZjcyZDNjYjVhMTQ4YTk2ZjYiLCJwZXJtaXNzaW9uIjp7InByb2ZpbGUiOiJhaG9qLmNvbS9maXJzdF9wcm9maWxlIiwicmVhZCI6dHJ1ZSwiY3JlYXRlIjp0cnVlLCJtb2RpZnkiOnRydWUsImRlbGV0ZSI6dHJ1ZX0sImNyZWF0ZWREYXRlIjoiMjAyNC0wMy0xOFQxNTozMTo1OC4xMTVaIiwiYXBwcm92ZWREYXRlIjpudWxsLCJleHBpcmF0aW9uRGF0ZSI6bnVsbCwiaWF0IjoxNzEwNzc1OTE4LCJleHAiOjExMTc4MDU1OTE4fQ.YxSUEYNCVRRRT-h7bmKrEULWyXgimd8W9-zFSLINknI",
"optionalMessage": "This is optional message for the permission from the app",
"__v": 0
},
{
"_id": "65faf9c8f9b73ae41344361f",
"app": {
"_id": "65f85d8f72d3cb5a148a96f6",
"nameDefinedByUser": "My New App",
"dateOfAssociationByApp": "2024-03-18T15:28:29.331Z",
"jwtTokenForPermissionRequestsAndProfiles": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBJZCI6IjY1Zjg1ZDhmNzJkM2NiNWExNDhhOTZmNiIsIm5hbWVEZWZpbmVkQnlVc2VyIjoiTXkgTmV3IEFwcCIsIm5hbWVEZWZpbmVkQnlBcHAiOiJhaG9qLmNvbSIsImlhdCI6MTcxMDc3NTcwOSwiZXhwIjoxMTE3ODA1NTcwOX0.EKgX4SevCgdCUq3QbpWbSahb47sbJL9o9hGGtfQIY10",
"dateOfRegistration": "2024-03-18T15:28:15.541Z",
"__v": 0,
"nameDefinedByApp": "ahoj.com"
},
"permission": {
"profile": "ahoj.com/first_profile",
"read": true,
"create": true,
"modify": true,
"delete": true,
"_id": "65faf9c8f9b73ae413443620"
},
"createdDate": "2024-03-20T14:59:20.695Z",
"approvedDate": null,
"isActive": false,
"revokedDate": null,
"expirationDate": null,
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhQWNjZXNzUGVybWlzc2lvbklkIjoiNjVmYWY5YzhmOWI3M2FlNDEzNDQzNjFmIiwiYXBwSWQiOiI2NWY4NWQ4ZjcyZDNjYjVhMTQ4YTk2ZjYiLCJwZXJtaXNzaW9uIjp7InByb2ZpbGUiOiJhaG9qLmNvbS9maXJzdF9wcm9maWxlIiwicmVhZCI6dHJ1ZSwiY3JlYXRlIjp0cnVlLCJtb2RpZnkiOnRydWUsImRlbGV0ZSI6dHJ1ZX0sImNyZWF0ZWREYXRlIjoiMjAyNC0wMy0yMFQxNDo1OToyMC42OTVaIiwiYXBwcm92ZWREYXRlIjpudWxsLCJleHBpcmF0aW9uRGF0ZSI6bnVsbCwiaWF0IjoxNzEwOTQ2NzYwLCJleHAiOjExMTc4MjI2NzYwfQ.yHg2A8plYpxhusRTqTFXwmhNj3sz0722mB5pRJCKyqY",
"optionalMessage": "This is optional message for the permission from the app",
"__v": 0
}
]
}
Approving Permission Request (admin part)
To approve a permission, there is /admin/api/permissions/approvePermissionRequest (PUT) endpoint for it.
You specify which permission request to approve by specifying permissionId. As you can see, each permission object in the permissions list in the responses above contains _id. This is the needed id.
{
"permissionId": "65ec875616c7c86638272a48"
}
And there are multiple responses types:
- permission was approved
{
"message": "Permission request approved successfully",
"data": {
"_id": "65faf9c8f9b73ae41344361f",
"app": "65f85d8f72d3cb5a148a96f6",
"permission": {
"profile": "ahoj.com/first_profile",
"read": true,
"create": true,
"modify": true,
"delete": true,
"_id": "65faf9c8f9b73ae413443620"
},
"createdDate": "2024-03-20T14:59:20.695Z",
"approvedDate": "2024-03-20T15:58:55.477Z",
"isActive": true,
"revokedDate": null,
"expirationDate": null,
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhQWNjZXNzUGVybWlzc2lvbklkIjoiNjVmYWY5YzhmOWI3M2FlNDEzNDQzNjFmIiwiYXBwSWQiOiI2NWY4NWQ4ZjcyZDNjYjVhMTQ4YTk2ZjYiLCJwZXJtaXNzaW9uIjp7InByb2ZpbGUiOiJhaG9qLmNvbS9maXJzdF9wcm9maWxlIiwicmVhZCI6dHJ1ZSwiY3JlYXRlIjp0cnVlLCJtb2RpZnkiOnRydWUsImRlbGV0ZSI6dHJ1ZX0sImNyZWF0ZWREYXRlIjoiMjAyNC0wMy0yMFQxNDo1OToyMC42OTVaIiwiYXBwcm92ZWREYXRlIjpudWxsLCJleHBpcmF0aW9uRGF0ZSI6bnVsbCwiaWF0IjoxNzEwOTQ2NzYwLCJleHAiOjExMTc4MjI2NzYwfQ.yHg2A8plYpxhusRTqTFXwmhNj3sz0722mB5pRJCKyqY",
"optionalMessage": "This is optional message for the permission from the app",
"__v": 0
}
}
permissionIdnot found
{
"message": "Permission request not found"
}
Revokig Permission Request (admin part)
If you find yourself in need of revoking a permission, this endpoint /admin/api/permissions/revokePermission (PUT) is there to save you.
Interface is similar to approving of permission request
{
"permissionId": "65c634fd1b6deae674c26af1"
}
And responses are similar as well.
Congratulations! Your app has now all permissions it needs! 🎉🎉🎉