Login

Connect your Backend with StackOne

The recommended way for connecting and authenticating accounts with the StackOne API is through your application backend. This keeps all secrets and sensitive data secure without exposing them in the frontend. This document describes some simple examples on how to implement an endpoint that can be used by your frontend application in NodeJS using Express.

A Connect Session is the mechanism for delegating the final stages of account linking to another user - usually to enter some final credentials - via a short-lived, custom token. The token settings describe what prompts are to be presented to the user. This is typically to enter their credentials for a given provider but it can also be configured to present a provider selection to them or to take them directly to editing a particular account. To support some advanced use cases it is also possible to control whether to allow multiple accounts with the same credentials.

Simple Use Case

To get started you need the StackOne API Key to successfully perform a request to get a token (via the Connect Sessions Endpoint).

When using the API to generate the connect session token there are a few different supported scenarios. The origin_owner_id and origin_owner_name are required fields but the origin_name is optional. If the origin_owner_id, origin_owner_name and provider have been used before then the account will be updated otherwise we will always create a new account.

In addition, adding the following fields can be used to control the behaviour of the connect session token.

FieldDescription
labelA label is a text field that can be used to store any string data against the account
categoryThe hub page will open at the category selector (HRIS, ATS etc) where the user can go through the remaining steps to complete adding the new account.
providerThe Hub page will open directly at the final stage where the user can enter the credentials and complete the last steps to complete adding the new account.
account_idIf an existing account id is included in the connect session then the hub will open on the Edit Account page where the credentials can be updated and the account can be re-linked

The following code demonstrates a basic implementation with all the required parameters:

app.post('/stackone_connect_sessions', jsonParser, async (req, res) => {
  const STACKONE_API_KEY = 'YOUR_STACKONE_API_KEY';

  const headers = {
    Authorization:
      'Basic ' + Buffer.from(STACKONE_API_KEY + ':' + '').toString('base64'),
  };

  // optional - metadata to be associated with the connection
  const metadata = { source: 'my-backend' };

  const { originUsername, provider } = req.body;

  const payload = {
    origin_owner_id: 'customer-123', // The organization id of the customer in your system
    origin_owner_name: 'Acme Inc', // The organization name to easily identify the owner of the connected account in StackOne
    origin_username: originUsername, // eg: '[email protected]' - an identifier for the user initiating the connection
    provider,
    metadata,
  };

  const requestOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...headers,
    },
    body: JSON.stringify(payload),
  };

  try {
    const responseWithToken = await fetch(
      'https://api.stackone.com/connect_sessions',
      requestOptions,
    );
    const { token } = await responseWithToken.json();
    res.send({ token });
  } catch (e) {
    res.status(500).send('error when trying to fetch session');
  }
});
from flask import Flask, request, jsonify
import requests
import json
import base64

app = Flask(__name__)

@app.route('/stackone_connect_sessions', methods=['POST'])
def stackone_connect_sessions():
    STACKONE_API_KEY = 'YOUR_STACKONE_API_KEY'
    headers = {
        'Authorization': 'Basic ' + base64.b64encode(f"{STACKONE_API_KEY}:".encode()).decode(),
    }
    metadata = {'source': 'my-backend'}
    req_data = request.json
    originUsername = req_data['originUsername']
    provider = req_data.get('provider', None)

    payload = {
        'origin_owner_id': 'customer-123',
        'origin_owner_name': 'Acme Inc',
        'origin_username': originUsername,
        'provider': provider,
        'metadata': metadata
    }

    try:
        response = requests.post(
            'https://api.stackone.com/connect_sessions',
            headers={**headers, 'Content-Type': 'application/json'},
            json=payload
        )
        token = response.json().get('token')
        return jsonify({'token': token})
    except Exception as e:
        return ('error when trying to fetch session', 500)

if __name__ == '__main__':
    app.run(debug=True)

using Microsoft.AspNetCore.Mvc;
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

[ApiController]
[Route("[controller]")]
public class StackOneConnectSessionsController : ControllerBase
{
    [HttpPost]
    public async Task<IActionResult> Post([FromBody] dynamic reqBody)
    {
        string STACKONE_API_KEY = "YOUR_STACKONE_API_KEY";
        string authHeader = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{STACKONE_API_KEY}:"));

        HttpClient client = new HttpClient();
        client.DefaultRequestHeaders.Add("Authorization", $"Basic {authHeader}");

        dynamic payload = new
        {
            origin_owner_id = "customer-123",
            origin_owner_name = "Acme Inc",
            origin_username = reqBody.originUsername,
            provider = reqBody.provider,
            metadata = new { source = "my-backend" }
        };

        try
        {
            var response = await client.PostAsync(
                "https://api.stackone.com/connect_sessions",
                new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json")
            );
            dynamic data = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
            return Ok(new { token = data.token });
        }
        catch (Exception)
        {
            return StatusCode(500, "error when trying to fetch session");
        }
    }
}

require 'sinatra'
require 'net/http'
require 'json'
require 'base64'

post '/stackone_connect_sessions' do
  STACKONE_API_KEY = 'YOUR_STACKONE_API_KEY'
  headers = {
    'Authorization' => 'Basic ' + Base64.strict_encode64("#{STACKONE_API_KEY}:"),
    'Content-Type' => 'application/json'
  }

  payload = {
    origin_owner_id: 'customer-123',
    origin_owner_name: 'Acme Inc',
    origin_username: params[:originUsername],
    provider: params[:provider],
    metadata: { source: 'my-backend' }
  }

  uri = URI('https://api.stackone.com/connect_sessions')

  begin
    response = Net::HTTP.post(uri, payload.to_json, headers)
    token = JSON.parse(response.body)['token']
    { token: token }.to_json
  rescue => e
    status 500
    'error when trying to fetch session'
  end
end

If the combination of origin_owner_id and origin_owner_name for a given provider has not previously been used this will create a new Account. If the origin_owner_id and origin_user_name values have already been used for a given provider then the existing account will be updated.

Fieldsdetails used before?DescriptionAccount action
origin_owner_id
origin_user_name
origin_name

category (optional)
provider (optional)
noA new account will be created. If the category is specified then the hub will open in the provider selection screen or if the provider is specified the hub will be opened with that provider pre-selected.create
origin_owner_id
origin_user_name
origin_name
yesThe existing account will be opened in edit modeupdate

In summary, the endpoint will send a POST request to the StackOne API /connect_sessions endpoint with the credentials and the request data. If the request is successful, it will respond with an object that contains a token property. This token will be returned and can then be used by the frontend to connect the React Hub with your application. When the frontend process is completed an Account will either be created or updated.

๐Ÿšง

The origin_owner_id should always be set via server-side logic and not be passed through directly via the client-side request.

Advanced Use Case

For most scenarios the simple use case described above should meet all requirements. To support some more advanced use cases we have introduced a new multiple flag. The multiple flag allows more control over the upsert behaviour on Accounts. In the simple use case above we saw how using an unused combination of origin_owner_id and origin_owner_name for a given provider would create a new Account but if we reused those values or specified an existing account_id then the existing account would be updated.

In some limited use cases you may wish to have multiple connected accounts for a given provider that are configured with the same originowner_id and origin_owner_name. If this behaviour is desired then you need to pass the _multiple flag set to true when the Connect Session is created. If the multiple flag is set then then any existing account with the same settings will be left untouched and a new account will be created.

Fieldsdetails used before?multiple flag set?DescriptionAccount action
origin_owner_id
origin_user_name
origin_name

category (optional)
provider (optional)
nonoA new account will be created. If the category is specified then the hub will open in the provider selection screen or if the provider is specified the hub will be opened with that provider pre-selected.create
origin_owner_id
origin_user_name
origin_name
yesnoThe existing account will be opened in edit modeupdate
origin_owner_id
origin_user_name
origin_name
yesyesA new account will be created. The account ids will be unique however in this multiple mode you may wish to use the label field so store any of your own data to distinguish these accountscreate
origin_owner_id
origin_user_name
origin_name
account_id
--The specified account will be opened for editing and will subsequently be updated.
The origin_owner_id must match the account_id or the connect session will not
update

Customising the hub behaviour

Per the Connect Sessions documentation, you can also specify a provider or categoriesproperty so the integration hub will directly filter or load the given integration (provider) or categories.

The values accepted in the provider property can be found in the Supported Providers list in the Provider Key column.

โš ๏ธ Any provider specified during the connect session must be enabled in the integrations page of the project.

If the provider is left undefined, the StackOne integrations hub will display a list of all integrations enabled for the project associated with the given API key.