Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion docs/API/components/email-verification.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,56 @@ Fliplet.Verification.Email.get()

The method returns a promise that resolves when the email verification component is rendered.

## What happens after successful verification

When a user successfully verifies their email or SMS code, Fliplet authenticates them with a `dataSource` passport session. This means the user stays logged in after verification and can be recognized by app security rules, data source security rules, and other APIs that rely on the current session.

Use `Fliplet.User.getCachedSession()` to read the authenticated entry:

```js
Fliplet.User.getCachedSession().then(function (session) {
var entry = _.get(session, 'entries.dataSource');

if (!entry) {
return; // user is not logged in with a dataSource passport
}

// Public session shape
// entry.id - the authenticated data source entry ID
// entry.dataSourceId - the authentication data source ID
// entry.data - the authenticated row's flat column values
console.log(entry);
});
```

A typical public session shape looks like this:

```js
{
entries: {
dataSource: {
id: 123,
dataSourceId: 456,
data: {
ID: 123,
Email: 'john@example.org',
Department: 'Sales',
Role: 'Member'
}
}
}
}
```

<p class="quote"><strong>Important:</strong> Email Verification does not only validate identity for the current screen. It creates a reusable logged-in session using the <code>dataSource</code> passport.</p>

This authenticated state is compatible with Data Source security rules:

- `allow: "loggedIn"` recognizes the user as authenticated
- {% raw %}`{{user.[Email]}}`, `{{user.[Department]}}`, `{{user.[Role]}}`, and `{{user.[ID]}}`{% endraw %} resolve against the authenticated row

See the <a href="../fliplet-session.html">Session JS APIs</a> and <a href="../../Data-source-security.html">Securing your Data Sources</a> docs for the full session and security model.

## Instance properties

The `verification` instance variable above makes available the following instance properties.
Expand Down Expand Up @@ -61,7 +111,7 @@ Fliplet.Verification.Email.get().then(function (verification) {

### Run code after email/SMS verification

The `onUserVerified` hook is fired after a user successfully validates their verification code (email or SMS). Use this to run custom logic such as redirecting users, fetching additional data, or setting encryption keys.
The `onUserVerified` hook is fired after a user successfully validates their verification code (email or SMS) and the `dataSource` passport session has been established. Use this to run custom logic such as redirecting users, fetching additional data, or setting encryption keys.

```js
Fliplet.Hooks.on('onUserVerified', function (data) {
Expand Down
2 changes: 1 addition & 1 deletion docs/API/components/login.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Fliplet.Hooks.on('sessionValidate', function (data) {
|----------|------|
| User logs in with username + password | `login` |
| User logs in via SAML2 SSO | `login` |
| User verifies via email or SMS code | `onUserVerified` (see [Email Verification](email-verification.html)) |
| User verifies via email or SMS code | `onUserVerified` (see [Email Verification](email-verification.html) for the hook, session shape, and security-rule compatibility) |
| Returning user's session is re-validated | `sessionValidate` |

<p class="quote"><strong>Tip:</strong> If you need to run the same code regardless of how the user authenticated, register handlers for both <code>login</code> and <code>onUserVerified</code>.</p>
Expand Down
11 changes: 8 additions & 3 deletions docs/API/fliplet-session.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,17 @@ Fliplet.Session.logout().then(function onSessionDestroyed() {

## Read details about connected accounts

If your app contains a login component (either DataSource, SAML2 or Fliplet) you can use the session to check whether the user is logged in and in and some of the connected account(s) details:
If your app contains an authentication component (for example Data Source Login, Email Verification, SMS verification, SAML2, or Fliplet login) you can use the session to check whether the user is logged in and read the connected account details:

```js
Fliplet.User.getCachedSession().then(function(session) {
if (session && session.entries) {
// the user is logged in;

// check if the user is connected to a dataSource login
// check if the user is connected to a dataSource passport
if (session.entries.dataSource) {
// user is logged in against a Fliplet dataSource
// user is logged in through a dataSource-based flow
// such as Data Source Login, Email Verification, or SMS verification
}

// check if the user is connected to a SAML2 login
Expand All @@ -101,6 +102,8 @@ Data for the connected account(s) can also be read and used as necessary:

### Example for dataSource login

This public session shape is used by any authentication flow that logs the user in with the `dataSource` passport, including Email Verification and SMS verification.

```js
Fliplet.User.getCachedSession().then(function (session) {
var user = _.get(session, 'entries.dataSource.data');
Expand All @@ -114,6 +117,8 @@ Fliplet.User.getCachedSession().then(function (session) {
});
```

<p class="quote"><strong>Note:</strong> For client-side app code, use <code>session.entries</code> as the public session interface. Do not rely on internal server/session structures.</p>

### Example for SAML2

```js
Expand Down
4 changes: 2 additions & 2 deletions docs/App-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ If you need more control on your security rules, you can also write your custom
- `session` (Object) the user's session, when available. Contains the same attributes found in the `v1/session` endpoint
- `ipRangeCheck` (Function) please check the next section on IP address whitelisting/blacklisting for usage

Here follows an example that protects all screens (aside from the `loginScreen`) from being accessed unless the user is logged in against a **dataSource** and the column `foo` of his user has value `bar`.
Here follows an example that protects all screens (aside from the `loginScreen`) from being accessed unless the user is logged in with a **dataSource** session, such as Data Source Login, Email Verification, or SMS verification, and the column `foo` of the authenticated row has value `bar`.

When those conditions are not met, an `error` is raised and the user is redirected (see `navigate`) to the `loginScreen`:

Expand Down Expand Up @@ -147,4 +147,4 @@ The two options can also be used together:

![Data Sources](https://user-images.githubusercontent.com/574210/197834498-dceeecdc-f5ac-4315-b629-dd8434c4a5b0.png)

---
---
54 changes: 53 additions & 1 deletion docs/Data-source-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ The `allow` property supports four modes:
{ "allow": "loggedIn" }
```

`allow: "loggedIn"` checks whether the current request is authenticated. This includes users authenticated through the `dataSource` passport, such as Data Source Login, Email Verification, and SMS verification.

<p class="quote"><strong>Important:</strong> <code>allow: "loggedIn"</code> only checks whether the user is authenticated. It does not limit which records they can access. Use <code>require</code> with {% raw %}<code>{{user[...]}}</code>{% endraw %} to scope access to the authenticated user's data.</p>

**Specific users** (filtered by session data). `allow.user` checks the logged-in user's **identity** — use it with literal values to control *who* can access. To control *which records* they can access, use `require` instead (see [Data requirements](#data-requirements-and-query-validation)):

```json
Expand Down Expand Up @@ -466,6 +470,8 @@ Condition values can reference the logged-in user's session data using Handlebar
- {% raw %}`{{user.[Role]}}`{% endraw %} — the user's role
- {% raw %}`{{user.[ID]}}`{% endraw %} — the user's data source entry ID

For Data Source Login, Email Verification, and SMS verification, these values come from the authenticated row in the authentication data source. For example, {% raw %}`{{user.[Email]}}`{% endraw %} resolves to the verified email address, and {% raw %}`{{user.[ID]}}`{% endraw %} resolves to the authenticated entry ID.

### Require syntax

**Required fields** (string) — the query must include these columns:
Expand Down Expand Up @@ -501,6 +507,52 @@ You can mix both formats in the same array:

For full examples of `require` in practice — including sample data, succeed queries, and fail queries — see [role-based access with protected fields](#example-role-based-access-with-protected-fields) and [department-scoped access](#example-department-scoped-access) above.

### Example: email verification with secured data access

The following rule allows authenticated users to read only the records that match their verified email address:

{% raw %}
```json
{
"type": ["select"],
"allow": "loggedIn",
"require": [
{ "Email": { "equals": "{{user.[Email]}}" } }
]
}
```
{% endraw %}

Client-side code must include a matching `where` clause:

```js
Fliplet.User.getCachedSession().then(function (session) {
var user = _.get(session, 'entries.dataSource.data');

if (!user) {
return;
}

return Fliplet.DataSources.connectByName('Orders').then(function (connection) {
return connection.find({
where: { Email: user.Email }
});
});
});
```

This succeeds because the user is authenticated and the query satisfies the rule's `require`.

The following query does not satisfy the rule:

```js
Fliplet.DataSources.connectByName('Orders').then(function (connection) {
return connection.find();
});
```

For reads, an unmet `require` means the rule is skipped. Access is only granted if a later rule allows it.

## Custom security rules

For advanced logic beyond what the standard rule properties support, you can write custom JavaScript security rules.
Expand Down Expand Up @@ -682,4 +734,4 @@ Both methods accept the following properties:
- `limit` (Number, defaults to `100`)
- `offset` (Number, defaults to `0`)

<p class="quote">Use <code>DataSources('Name')</code> (data source name) instead of <code>DataSources(123)</code> (ID) in custom scripts. Data source names are preserved during app clone, so name-based lookups continue to work without manual remapping.</p>
<p class="quote">Use <code>DataSources('Name')</code> (data source name) instead of <code>DataSources(123)</code> (ID) in custom scripts. Data source names are preserved during app clone, so name-based lookups continue to work without manual remapping.</p>