...
The API-Key User will be used in all User references (for instance lock info) and
must not be deleted: It is a placeholder user for all the end users who don't have an
account on our dashboard. The password authentication of this user - even if possible - is never used.
...
Roles
To access the review page in the Contract Fit's dashboard you need to grant 2 different roles to the API-Key
so that the user has access to all required functions:
One Role which grants access to view_list but no access to review nor submit
One Role which grants access to review and submit
The first role will be used to access inbox related settings and data, and the second one will restrict the
user to a single document if its scope is a document. By using inbox as scope, the user will be granted the
review role on all doc in the inbox.
Info |
---|
If you grant review and submit to the first role, the user will have access to all docs in the inbox |
In this diagram:
...
Since John has a regular account, his user roles allow him to access inbox A & B
Using hPym5P API-Key, only inbox A and the document 1 page (will be accessible - not document 2) will be accessible
Using doCWk4 API-Key, only inbox A and the document 2 page (will be accessible - not document 1) will be accessible
Using RAck9j API-Key, only inbox B and all documents in it but no document will be accessible
Info |
---|
The placeholder user must also have the permissions set in the API-Keys: adding the same 2 roles is enough |
Flow example
on your dashboard, add a button "Go to document review" on the doc page
on click, a call is made to your back-end
your back-end calls Contract Fit API and obtains a new API-Key scoped to the specific document
your back-end generates the fully qualified link to the doc
your back-end redirects the user to the Contract Fit dashboard using the link
your end user obtains a session derived from the API-Key roles and is logged in
after review, your end user returns to your dashboard and mark the doc as done
your back-end revokes the API-Key to avoid abuse
the API-Key cannot be used anymore
...
a User on your tenant with enough permissions to set up the authentication
permissions: edit_backend_settings and view_api_keys
this user is only used to make the setup calls, you must not use it as the base user for the API-Key!
a dedicated User on your tenant who will be bound to your API-Key
a Role (or more) at least 2 roles to grant to the end user
Scoped to an inbox or to a (document, inbox) combinationone Role for the inbox related permissions
one Role for the review related permissions
Code Block | ||
---|---|---|
| ||
import requests from secrets import token_urlsafe from getpass import getpass tenant = "https://alfredo.contract-q.fit" admin = "timothe@contract.fit" password = getpass(f"User {admin} password: ") sess = requests.Session() res = requests.post(f"{tenant}/admin/auth", json={ "username": admin, "password": password }) res.raise_for_status() jwt = res.json()["authentication_token"] sess.headers = dict(Authorization=f"Bearer {jwt}") |
...
Code Block | ||
---|---|---|
| ||
res = sess.get(f"{tenant}/admin/inboxes") res.raise_for_status() inboxes = res.json() invoice_inbox = next(filter(lambda x: x["name"] == "invoice", inboxes)) |
Create
...
roles
One time only: use / create a simple role roles with as little permissions as possible.
We'll create 2 roles:
InboxGuest granting only the view_list read_thresholds_settings and edit_format_settings permissions
ReviewGuest granting review & submit.
You can grant additional permissions, but be careful not to give too broad permissions
Code Block | ||
---|---|---|
| ||
permissionsfrom =functools {import partial def "view_statistics": True,create_or_update_role(name, perms): ""upload": False, Create #the werole don't want our users to be able to upload using this rolenamed *name* or update its permissions with the ones provided as *perms* "review"": True, r = "submit": True,sess.get(f"{tenant}/admin/roles") r.raise_for_status() try: "view_list": True,role = next(filter(lambda x: x["name"] == name, r.json())) "read_thresholds_settings": True, except StopIteration: func = "escalate_document": True,partial(sess.post,f"{tenant}/admin/roles") else: } resfunc = partial(sess.post(patch, f"{tenant}/admin/roles", /{role['id']}") r = func(json={"name": "ReviewGuest"name, "permissions": perms }) r.raise_for_status() return r.json() permissions = { "permissionsview_list": permissionsTrue, "read_thresholds_settings": True, "edit_format_settings": True } rolename = "InboxGuest" inbox_role = create_or_update_role(rolename, permissions) permissions = { "review": True, "submit": True, "escalate_document": True, }) res.raise_for_status() rolename = "ReviewGuest" review_role = res.json() create_or_update_role(rolename, permissions) |
Create dedicated user
One time only: create the guest placeholder user. All end users using the API-Keys will be seen as this user.
The User must have equal or broader role and permissions than the API-Keys will require.
Code Block | ||
---|---|---|
| ||
resdef create_or_update_user(name, roles=None): """ Create the user named *name* or update its roles """ if roles is None: roles = [] kwargs = dict( username=name, roles=roles ) r = sess.postget(f"{tenant}/admin/users", json={) r.raise_for_status() try: u = next(filter(lambda x: x["username":"shared-link",] == name, r.json())) "active": True,except StopIteration: func = "password":token_urlsafe(18),partial(sess.post,f"{tenant}/admin/users") # The user password does not matter, use a randomly generated string kwargs["password"] = token_urlsafe(18) kwargs["roles": [active"] = True else: func = partial(sess.patch, f"{tenant}/admin/users/{u['id']}") r = func(json=kwargs) r.raise_for_status() return r.json() username = "guest" # the user must have the permissions we will give to our API-Keys user = create_or_update_user(username, roles=[ {"role": inbox_role["id"],"inbox": invoice_inbox["id"]}], }) res.raise_for_status() user = res.json() {"role": review_role["id"],"inbox": invoice_inbox["id"]} ]) |
Create API-Key
Each time you need to create a fully qualified link with a new scope (ie. new doc),
you need to create a new key with the new scopes.
...
If you want to limit the API-Key to a single doc, you can specify the document scope but you also need to specify the
inbox scope, so that your end user enduser has access to all required features for the review page.
...
To give access to a specific document you must also specify the inbox of the document within the same in another role definition; you can add multiple independent roles in the roles list, each one giving access to a single inbox or a (inbox, document) combination.
Code Block | ||
---|---|---|
| ||
doc_id = "60ddb937b260064252bd5a9860ddc81dd50d836c8dfa13ea" # your doc ID key_roles = [ {"role": inbox_role["id"], "inbox": invoice_inbox["id"]}, # grant InboxRole on the inbox {"role": review_role["id"], "document_id": doc_id} # samegrant roleReviewGuest as the user but limited restricted to one doc ] res = sess.post(f"{tenant}/admin/auth/api-key", json={ "user": user["id"], "roles": key_roles }) res.raise_for_status() token = res.json()["token"] |
...
To pass the API-Key to Contract Fit's dashboard, you need to pass it in the
query string querystring parameter named nonce :
Code Block | ||
---|---|---|
| ||
url = f"{tenant}/#/view/{doc_id}?nonce={token}" print(url) |
...