# How an application connects to OpenPlatform: the launch and the verification

> The exact handshake between OpenPlatform and an application: the address it is opened with, how the application signs its request to /verify/ and the user data it gets back.

Framework: openplatform
Product: OpenPlatform (openplatform@5)
Language: en
Content-SHA256: 6ca3284d8734f1ae0f727ee0443412c5cba13f9a157aeba40684870245c05268
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: 
Review: not-recorded

When a user opens an application, OpenPlatform does not send a password or a cookie to it. It sends a **one-time launch address**, and the application calls back to OpenPlatform to learn who the user is. This page follows the code (`schemas/account.js`, action `Account/run`, and `controllers/verify.js`).

## 1. The launch

When the user clicks an application, the portal calls the API `run/{appid}`. OpenPlatform:

1. checks that the application is in the list of the user (`App not found` otherwise) and that it is not disabled;
2. creates a session of the application (table `tbl_app_session`) that expires after the setting `app_session_expire` (one day by default);
3. builds the **verification address**: the platform `url` + `/verify/?token=` + the identifier of the session joined to the identifier of the installation with `X`, followed by `X` and a checksum (`FUNC.checksum`, which uses the secret `saltchecksum`);
4. derives the two tokens of that session from the shared secrets of the application:
   - `reqtoken` = the MD5 of the verification address salted with the `reqtoken` of the application, in lower case;
   - `restoken` = the MD5 of that `reqtoken` salted with the `restoken` of the application;
5. opens the application at its `url` with one extra query parameter: `openplatform=<verification address>~<reqtoken>`.

For an application marked as a bookmark there is no handshake: the address gets `ssid=<session checksum>` instead.

## 2. The verification

The application takes the value of `openplatform`, which is the verification address, a `~` and the `reqtoken` of the session, and:

1. computes **its own** `restoken`: the MD5 of the `reqtoken` salted with the `restoken` that it shares with OpenPlatform;
2. calls `GET` on the whole value of `openplatform` (the `~` and the `reqtoken` stay in the query string) with the header `x-token` set to that `restoken`.

OpenPlatform then (`controllers/verify.js`):

1. splits the query token at the last `~` (the part after it is the `reqtoken` that it sent) and refuses the call when the header or the token is missing;
2. checks the checksum of the session identifier, reads the session and compares both secrets (`reqtoken` and the `restoken` of the header); any difference is `Invalid token`;
3. if the application has a list of allowed addresses, checks the address of the caller (`Not allowed IP address`);
4. reads the user and refuses a disabled user (`User has been disabled`) or an inactive one (`User is inactive`);
5. makes sure the user has the notification links of this application (table `tbl_user_app`);
6. builds the answer and passes it through the transformation `verify` of the platform, so a deployment can add fields.

The answer is a JSON object. Empty values are dropped from it. Its main fields are:

| Field | What it is |
|---|---|
| `id`, `name`, `email`, `photo`, `gender`, `reference` | who the user is (`photo` is an absolute address) |
| `language`, `color`, `interface`, `darkmode`, `sounds` | the preferences (the platform language and colour when the user has none) |
| `sa` | the user is an administrator of the platform |
| `permissions` | the `value` strings of the permissions of the user in this application |
| `groups` | the ids of the groups of the user |
| `appid`, `ssid` | the application and the checksum of its session |
| `openplatformid`, `openplatform` | the identifier and the address of the installation |
| `iframe` | `true` unless the application is external |
| `notify` | the address to send notifications to, when the user accepts them ([notifications](/en/openplatform/notifications-and-public-api/)) |
| `platform` | the `name` and `logo` of the platform, its `groups` and the applications of the user |

The answer is kept in an in-memory cache keyed by the session token (the part before the `~`) and the cache is cleared every two minutes. A call with a token that is in that cache is answered from it, before the secrets are compared again, so a repeated verification inside that time is cheap.

## 3. Asking again later

`GET /session/` takes the `ssid` that the application received (it also accepts `openplatformid`, `token` and `session` as the name of the parameter), checks its checksum and returns the user (`id`, `language`, `name`, `color`, `sa`, `isonline`) while the session of the user has not expired.

## What to remember when you build the application

- Never ship the shared secrets to the browser: only the server of the application needs them.
- Verify on the **server** and create your own session from the answer; the `openplatform` parameter is for one launch.
- Use the `permissions` of the answer, not a role that the browser sends.
- Total.js 5 has a native client for this family of protocols: see [OPENCLIENT](/en/total5/openclient-protocol/).
