Skip to content

Commit

Permalink
Improve authorization guide
Browse files Browse the repository at this point in the history
  • Loading branch information
bastienbeurier committed Nov 26, 2024
1 parent 144ad51 commit 9ac6698
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 96 deletions.
30 changes: 15 additions & 15 deletions docs-v2/guides/authorize-an-api-from-your-app-with-custom-ui.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ sidebarTitle: 'Authorize an API from you app (custom UI)'
description: 'Step-by-step guide on getting user authorization with your own UI.'
---

# Authorize users from your app using your own UI
<Info>
Pre-requisites:
- complete the [_Configure an integration_ guide](/guides/getting-started/configure-an-integration)
- generate a [Connect session token](/guides/getting-started/authorize-an-api-from-your-app#generate-a-session-token-backend)
</Info>

## Integrate the frontend SDK

Once you have tested that the authorization flow works for your own external account, you can trigger authorization flows for your customers from your app with the Nango SDK.

Get your `Public Key` from the _Environment Settings_ tab.

In your frontend, initiate Nango ([reference](/reference/sdks/frontend#instantiate-the-frontend-sdk)):

```ts
import Nango from '@nangohq/frontend';

const nango = new Nango({ connectSessionToken: '<CONNECTION-SESSION-TOKNE>' });
const nango = new Nango({ connectSessionToken: '<CONNECT-SESSION-TOKEN>' });
```

Initiate the authorization flow ([reference](/reference/sdks/frontend#collect-and-store-end-user-credentials)):
Expand Down Expand Up @@ -85,19 +85,17 @@ nango

</Tabs>

<Tip>
Nango will automatically collect, store, and refresh the API credentials as needed.
</Tip>

## APIs requiring connection-specific configuration for authorization
## Handle APIs requiring connection-specific configuration for authorization

Some APIs require connection-specific configuration (e.g. Zendesk, Shopify).

For example, Zendesk has the following authorization URL, where the subdomain is specific to a user's Zendesk account:

`https://<USER-SUBDOMAIN>.zendesk.com/oauth/authorizations/new`

For these cases, you must provide this configuration when calling `nango.auth()` ([reference](/reference/sdks/frontend#collect-and-store-end-user-credentials)):
When using the [Connect UI](/guides/getting-started/authorize-an-api-from-your-app#option-1-use-the-nango-connect-ui), this information is collected from the end user with an automatically-generated form.

But when using a custom UI, you must provide this configuration when calling `nango.auth()` ([reference](/reference/sdks/frontend#collect-and-store-end-user-credentials)):

```js
nango.auth('zendesk', {
Expand All @@ -113,11 +111,13 @@ nango.auth('zendesk', {
});
```

This _connection configuration_ is stored in the connection. You can retrieve it with the SDK ([reference](/reference/sdks/node#get-a-connection-with-credentials)), API ([reference](/reference/api/connection/get)), and the Nango UI.
This _connection configuration_ is stored in the connection. You can retrieve it with the SDK ([reference](/reference/sdks/node#get-a-connection-with-credentials)) and API ([reference](/reference/api/connection/get)), or see it in connection details in the Nango UI.

# Troubleshoot authorization errors
# Next

If an authorization request fails, you can analyze the relevant log in the _Logs_ tab of the Nango UI.
<Info>
Once the authorization succeeds, follow these instructions [instructions](/guides/getting-started/authorize-an-api-from-your-app#save-the-connection-id-backend) to finish the authorization flow implementation.
</Info>

<Tip>
**Questions, problems, feedback?** Please reach out in the [Slack community](https://nango.dev/slack).
Expand Down
2 changes: 1 addition & 1 deletion docs-v2/guides/customize/create-a-custom-integration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: 'Step-by-step guide on how to create a custom integration with Nang
In Nango, integration use-cases are mapped to [syncs](/understand/concepts/syncs) and [actions](/understand/concepts/actions). Before starting, determine if a sync, an action, or a combination of both fits your use case.

<Info>
Pre-requisite: completion of the [_Set up the CLI and folder_ guide](/guides/customize/setup).
Pre-requisite: complete the [_Set up the CLI and folder_ guide](/guides/customize/setup).
</Info>

# Edit the `nango.yaml` configuration
Expand Down
164 changes: 87 additions & 77 deletions docs-v2/guides/getting-started/authorize-an-api-from-your-app.mdx
Original file line number Diff line number Diff line change
@@ -1,40 +1,67 @@
---
title: 'Authorize users from your app'
sidebarTitle: 'Authorize users from your app'
description: 'Step-by-step guide on getting user authorization to access an external API, from your application.'
description: 'Step-by-step guide to getting user authorization to access an external API from your application.'
---

<Info>
Pre-requisite: completion of the [_Configure an integration_ guide](/guides/getting-started/configure-an-integration).
Pre-requisite: complete the [_Configure an integration_ guide](/guides/getting-started/configure-an-integration).
</Info>

Nango Connect requires a unique temporary token to securely authenticate your users.
# Generate a session token (backend)

<img src="/images/connect-ui/steps.png" alt="Nango Connect UI required steps" />
In **your backend**, set up an API endpoint that your frontend will call. This endpoint should request a session token from Nango and return it to the frontend.

<Tip>You can check a live implementation in our <a href="https://github.com/NangoHQ/sample-app?rel=connect-ui-guide"> Sample App</a></Tip>
Here's an example of how to generate a session token using Nango's API ([API ref](/reference/api/connect/sessions/create) / [SDK ref](/reference/sdks/node#create-a-connect-session)):

## Step 1: Generate a Session token
<Tabs>

To securely authenticate your users, we need a dedicated token generated on your backend and passed to the frontend. This security measure allows us to strictly identify authenticated users and pre-filter allowed integrations.
<Tab title="cURL">

On **your backend**, you need an API endpoint that your frontend contacts, which will then communicate with the Nango API. Once you get back the token, forward it to Nango Connect.
This token has a lifespan of 30 minutes after which it expires.
```bash
curl --request POST \
--url https://api.nango.dev/connect/sessions \
--header 'Authorization: Bearer <NANGO-SECRET-KEY>' \
--header 'Content-Type: application/json' \
--data '{
"end_user": {
"id": "<END-USER-ID>",
"email": "<END-USER-EMAIL>",
"display_name": "<OPTIONAL-END-USER-DISPLAY-NAME>"
},
"organization": {
"id": "<OPTIONAL-ORG-ID>",
"display_name": "<OPTIONAL-ORG-DISPLAY-NAME>"
},
"allowed_integrations": [
"<INTEGRATION-ID>"
]
}'

```

```javascript
</Tab>

<Tab title="Node">

```ts
import { Nango } from '@nangohq/node';

const nango = new Nango({ secretKey: process.env['NANGO_SECRET_KEY'] });
const nango = new Nango({ secretKey: process.env['<NANGO-SECRET-KEY>'] });

api.post('/sessionToken', (req, res) => {
// Ask Nango for a secure token
const res = await nango.createConnectSession({
end_user: {
id: user.id,
email: user.email,
display_name: user.displayName,
id: '<END-USER-ID>',
email: '<END-USER-EMAIL>',
display_name: '<OPTIONAL-END-USER-DISPLAY-NAME>',
},
allowed_integrations: ['bamboohr'],
organization: {
id: '<OPTIONAL-ORG-ID>',
display_name: '<OPTIONAL-ORG-DISPLAY-NAME>'
},
allowed_integrations: ['<INTEGRATION-ID>'],
});

// Send this token back to your frontend
Expand All @@ -43,79 +70,63 @@ api.post('/sessionToken', (req, res) => {
});
});
```
</Tab>

<Card title="POST /connect/sessions" icon="code" href="/reference/api/connect/sessions/create" horizontal>
Not using the SDK? Check our HTTP API reference
</Card>

## Step 2: Trigger Auth Flow
</Tabs>

In **your frontend**, you need to load our SDK, get the Session Token from Step 1 and open Nango Connect
<Accordion title="Clarifying end user and organization information">
The `end_user` and `organization` information are primarily used for display purposes in the Nango UI and, in some cases, for custom billing plans. These fields help identify which connection belongs to which end user and/or organization.

```js
import Nango from '@nangohq/frontend';

const nango = new Nango();
const connect = nango.openConnectUI();
Required fields:
- `end_user.id`: Your internal ID of the user who initiated the authorization flow.
- `end_user.email`: The email of the user who initiated the authorization flow.

// Call the endpoint created in Step 1
const res = await fetch('/sessionToken', { method: 'POST' });
connect.setSessionToken(res.sessionToken);
```
While some connections may belong to an organization rather than a specific user, in most cases, a user initiates the authorization flow. In such scenarios:
- You should store the user’s ID and email along with the relevant organization details. Sometimes, the user email in your app will not match the email they use to connect their external account, which is fine.
- If you don’t have a user ID or email, you can use placeholders. This won’t affect how Nango operates.

<Tip>It's recommended to set the `sessionToken` asynchronously to be able to display the UI loading to your users before it's ready for better UX</Tip>
<Info>
The user’s email is used in the Nango UI to retrieve & display their company’s logo, improving visual clarity.
</Info>
</Accordion>

## Step 3: Link Connection ID to your user
## Trigger the auth flow (frontend)

In **your frontend**, the Connect UI will send back an event when a user connects or closes the modal. You can register an event listener and respond appropriately.
In **your frontend**, load the Nango frontend SDK, retrieve the session token from the backend, and trigger the authorization flow.

When a user completes a flow, you will receive a `connect` event. This event contains the `providerConfigKey`, which is the id of your integration and a `connectionId`, which is the auto-generated id that represents the couple user + integration.
### Option 1: Use the Nango Connect UI

```js
[...]

function saveConnectionId(authResults) {
await fetch('/connection', { method: 'POST', body: authResults });
}

nango.openConnectUI({
sessionToken: await getSessionToken(),
import Nango from '@nangohq/frontend';

// Listen to events
const nango = new Nango();
const connect = nango.openConnectUI({
onEvent: (event) => {
if (event.type === 'connect') {
void saveConnectionId(event.payload);
if (event.type === 'close') {
// Handle modal closed.
} else if (event.type === 'connect') {
// Handle auth flow successful.
}
},
});
```

In your backend, associate this connectionId to your end user.

```javascript
api.post('/connection', (req, res) => {
await User.update({
connectionId: req.body.connectionId,
integrationId: req.body.providerConfigKey,
});

res.status(200).send({
success: true
});
});
const res = await fetch('/sessionToken', { method: 'POST' }); // Retrieve the session roken from your backend.
connect.setSessionToken(res.sessionToken); // A loading indicator is shown until this is set.
```

<Tip>If you have multiple integrations you will have to store multiple `connectionId`s</Tip>
### Option 2: Use your custom UI

Refer to the [_Authorize an API from your app with custom UI_ guide](/guides/authorize-an-api-from-your-app-with-custom-ui) for details on implementing a custom user interface.

## Listen for webhooks
## Save the Connection ID (backend)

Your backend is notified by Nango when an authorization attempt is completed, successful or not.
Your backend will receive a notification from Nango when an authorization attempt is completed.

To set this up:
1. go to the _Environment Settings_ tab
2. specify a _Webhook URL_ to which Nango will send notifications
3. listen for webhooks in your backend at the specified route
4. enable the "Send New Connection Creation Webhooks" checkbox
1. go to the _Environment Settings_ tab in the Nango UI
2. specify a _Webhook URL_ where Nango should send notifications
3. enable the _Send New Connection Creation Webhooks_ option
4. create the specified route in your backend to handle Nango webhooks

Nango webhooks are post requests with the following JSON body:
```json
Expand All @@ -132,21 +143,20 @@ Nango webhooks are post requests with the following JSON body:
}
```

For each successful authorization attempt, persist the connection ID & integration ID in your database. You will need them to retrieve the connection credentials later.

<Info>
Before using Nango in production, we advise [verifying webhook signatures](/guides/verify-webhooks-from-nango).
</Info>

# You are ready
For each successful authorization attempt, persist the connection ID. This ID is required to retrieve connection credentials later.

Your users can now launch Nango Connect and connect to any of your integrations, Nango is taking care of the rest.
# Troubleshoot authorization errors

If an authorization request fails, you can analyze the relevant log in the _Logs_ tab of the Nango UI.

<Card title="Want to build your own UI?" icon="code" href="/guides/authorize-an-api-from-your-app-with-custom-ui" horizontal>
Use the Headless API to create your custom experience
</Card>
# You are ready

You have successfully set up the authorization flow for your users. Next steps:
- View new connections in the _Connections_ tab of the Nango UI
- Retrieve connection credentials with the [API](/reference/api/connection/get) or [SDK](/reference/sdks/node#get-a-connection-with-credentials)
- [Read data](/guides/getting-started/read-from-an-api) from the API
- [Write data](/guides/getting-started/write-to-an-api) to the API
- [Proxy request](/guides/getting-started/proxy-requests-to-an-api) to the API

<Tip>
**Questions, problems, feedback?** Please reach out in the [Slack community](https://nango.dev/slack).
Expand Down
2 changes: 1 addition & 1 deletion docs-v2/guides/getting-started/read-from-an-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: 'Step-by-step guide on how to continuously sync data from an API (u
---

<Info>
Pre-requisite: completion of the [_Configure an integration_ guide](/guides/getting-started/configure-an-integration).
Pre-requisite: complete the [_Configure an integration_ guide](/guides/getting-started/configure-an-integration).
</Info>

# Activate a sync template
Expand Down
2 changes: 1 addition & 1 deletion docs-v2/guides/getting-started/write-to-an-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: 'Step-by-step guide on how to write to an API (using an action temp
---

<Info>
Pre-requisite: completion of the [_Configure an integration_ guide](/guides/getting-started/configure-an-integration).
Pre-requisite: complete the [_Configure an integration_ guide](/guides/getting-started/configure-an-integration).
</Info>

# Activate an action template
Expand Down
2 changes: 1 addition & 1 deletion docs-v2/guides/proxy-requests-to-an-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: 'Step-by-step guide on how to proxy requests to an API (using the _
---

<Info>
Pre-requisite: completion of the [_Configure an integration_ guide](/guides/getting-started/configure-an-integration).
Pre-requisite: complete the [_Configure an integration_ guide](/guides/getting-started/configure-an-integration).
</Info>

The [Proxy](/understand/concepts/proxy) lets you query external APIs easily with credentials injection, request logging, and pre-configurations for base URLs, rate-limits, retries, etc.
Expand Down
Binary file removed docs-v2/images/connect-ui/steps.png
Binary file not shown.

0 comments on commit 9ac6698

Please sign in to comment.