Authentication

To access Membrane through the REST API or Front-end SDK, you need an access token that contains information about your workspace, permissions, and the customer using the integration.

Step 1: Token Data Structure

Authentication token contains information Membrane needs to know about your user:

id - User ID, unique within the workspace

name - Username to identify the user in the Membrane UI

fields - Any additional information you want to store about the user (e.g., API key for Membrane to call your API on behalf of this user, or user preferences for integrations)

Step 2: Workspace Key/Secret Token Signing

To authenticate, create a JSON Web Token with your user's data. Workspace Key/Secret token signing uses symmetric encryption with your workspace key and secret. You can find them on the Settings page.

Generate a JWT token using your workspace key and secret

import jwt from "jsonwebtoken"
// Your workspace key and secret.
// You can find them on the Settings page.
const WORKSPACE_KEY = "<WORKSPACE_KEY>"
const WORKSPACE_SECRET = "<WORKSPACE_SECRET>"

const tokenData = {
  // Key of your workspace
  workspaceKey: WORKSPACE_KEY,
  // Identifier of your customer (user, team, or organization).
  id: "{CUSTOMER_ID}",
  // Human-readable customer name.
  name: "{CUSTOMER_NAME}",
  // (optional) Any user fields you want to attach to your customer.
  fields: {
    userField: "<user field value>",
  },
}

const options = {
  // To prevent token from being used for too long
  expiresIn: 7200,
  // HS256 signing algorithm is used by default,
  // but we recommend to go with more secure option like HS512.
  algorithm: "HS512",
}

const token = jwt.sign(tokenData, WORKSPACE_SECRET, options)
import datetime
import jwt

# Your workspace key and secret.
# You can find them on the Settings page.
WORKSPACE_KEY = "<WORKSPACE_KEY>"
WORKSPACE_SECRET = "<WORKSPACE_SECRET>"

encoded_jwt = jwt.encode(
    {
      # ID of your customer in your system.
      # It will be used to identify customer in Membrane
      "id": "{CUSTOMER_ID}",
      # Human-readable name (it will simplify troubleshooting)
      "name": "{CUSTOMER_NAME}",
      "iss": WORKSPACE_KEY,
      # Any customer fields you want to attach to your user.
      "fields": {
        "field1": "<field value>"
      },
      "exp": datetime.datetime.now() + datetime.timedelta(seconds=1440)
    }, WORKSPACE_SECRET, algorithm="HS256")
import (
    "time"
    "github.com/golang-jwt/jwt/v5"
)

var WORKSPACE_KEY = "<WORKSPACE_KEY>"
var WORKSPACE_SECRET = "<WORKSPACE_SECRET>"

var SigningKey = []byte(WORKSPACE_SECRET)

claims := jwt.MapClaims{
    // Identifier of your customer (user, team, or organization).
    "id" : "{CUSTOMER_ID}",
    // Human-readable customer name.
    "name": "{CUSTOMER_NAME}",
    // To prevent token from being used for too long
    "exp": time.Now().Add(time.Hour * 24).Unix(),
    "iss": WORKSPACE_KEY,
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString(SigningKey)
require 'jwt'

WORKSPACE_SECRET = '<WORKSPACE_SECRET>'
WORKSPACE_KEY = '<WORKSPACE_KEY>'

payload = {
  id: '{CUSTOMER_ID}',
  name: '{CUSTOMER_NAME}',
  iss: WORKSPACE_KEY,
  exp: Time.now.to_i + 60 * 60 * 6, # Expiration time (6 hours from now)
}

token = JWT.encode(payload, WORKSPACE_SECRET, 'HS256')
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import javax.crypto.spec.SecretKeySpec;
import java.time.temporal.ChronoUnit;
import java.util.Date;

String workspaceKey = "<WORKSPACE_KEY>";
String workspaceSecret = "<WORKSPACE_SECRET>";

String jwtToken = Jwts.builder()
        .claim("id", "{CUSTOMER_ID}") // Identifier of user or organization.
        .claim("name", "{CUSTOMER_NAME}") // Human-readable name (it will simplify troubleshooting)
        // .claim("fields", <user fields value>) (optional) Any user fields you want to attach to your user.
        .setExpiration(Date.from(new Date().toInstant().plus(14400, ChronoUnit.SECONDS))) // To prevent token from being used for too long
        .setIssuer(workspaceKey)
        .signWith(new SecretKeySpec(workspaceSecret.getBytes(), SignatureAlgorithm.HS256.getJcaName()), SignatureAlgorithm.HS256)
        .setHeaderParam("typ", "JWT")
        .compact();
use Firebase\JWT\JWT;

// Your workspace key and secret.
// You can find them on the Settings page.
$secret = '<WORKSPACE_SECRET>';
$key = '<WORKSPACE_KEY>';

$payload = [
    'id' => "{CUSTOMER_ID}",  // ID of your customer in your system. It will be used to identify customer in Membrane
    'name' => "{CUSTOMER_NAME}", // Human-readable customer name (it will simplify troubleshooting)
    'iss' => $key,
    'exp' => time() + 60 * 60 * 6, // To prevent token from being used for too long
];
$token = JWT::encode($payload, $secret, 'HS256');
ℹ️

Security recommendation

Default algorithm for signing tokens is HS256, but we recommend using a more secure option like ES256 or RS256. We support all algorithms supported by the jsonwebtoken library. See the jsonwebtoken algorithms for details.

Step 3: Public/Private Key Token Signing

Alternatively, you can use a public/private key pair to sign the token. This is a more secure option. Pass the private key to the sign method and provide the public key in the Workspace Settings.

Generate a JWT token using public/private key pair

import jwt from "jsonwebtoken"

// Your workspace key.
// You can find it on the Settings page.
const WORKSPACE_KEY = "<WORKSPACE_KEY>"

// Do not expose your private key to anyone. You should only use it to sign tokens.
const PRIVATE_KEY = `<YOUR PRIVATE KEY>`

const tokenData = {
  // Identifier of user or organization.
  id: "{CUSTOMER_ID}",
  // Human-readable name (it will simplify troubleshooting)
  name: "{CUSTOMER_NAME}",
  // (optional) Any user fields you want to attach to your user.
  fields: {
    userField: "<user field value>",
  },
}

const options = {
  issuer: WORKSPACE_KEY,
  // To prevent token from being used for too long
  expiresIn: 7200,
  algorithm: "ES256", // or any other asymmetric algorithm you prefer (RS*, ES*, PS*)
}

const token = jwt.sign(tokenData, PRIVATE_KEY, options)
import datetime
import jwt

# Your workspace key.
# You can find it on the Settings page.
WORKSPACE_KEY = "<WORKSPACE_KEY>"

# Do not expose your private key to anyone. You should only use it to sign tokens.
PRIVATE_KEY = """<YOUR PRIVATE KEY>"""

encoded_jwt = jwt.encode(
    {
      # ID of your customer in your system.
      # It will be used to identify customer in Membrane
      "id": "{CUSTOMER_ID}",
      # Human-readable name (it will simplify troubleshooting)
      "name": "{CUSTOMER_NAME}",
      "iss": WORKSPACE_KEY,
      "exp": datetime.datetime.now() + datetime.timedelta(seconds=1440)
    }, PRIVATE_KEY, algorithm="ES256")
import (
    "time"
    "github.com/dgrijalva/jwt-go"
    "crypto/ecdsa"
    "crypto/x509"
    "encoding/pem"
)

var WORKSPACE_KEY = "<WORKSPACE_KEY>"

// Do not expose your private key to anyone. You should only use it to sign tokens.
var PRIVATE_KEY = []byte(`<YOUR PRIVATE KEY>`)

block, _ := pem.Decode(PRIVATE_KEY)
privateKey, _ := x509.ParseECPrivateKey(block.Bytes)

claims := jwt.MapClaims{
    // Identifier of your customer (user, team, or organization).
    "id" : "{CUSTOMER_ID}",
    // Human-readable customer name.
    "name": "{CUSTOMER_NAME}",
    // To prevent token from being used for too long
    "exp": time.Now().Add(time.Hour * 24).Unix(),
    "iss": WORKSPACE_KEY,
}

token := jwt.NewWithClaims(jwt.SigningMethodES256, claims)
tokenString, err := token.SignedString(privateKey)
require 'jwt'
require 'openssl'

WORKSPACE_KEY = '<WORKSPACE_KEY>'

# Do not expose your private key to anyone. You should only use it to sign tokens.
PRIVATE_KEY = OpenSSL::PKey::EC.new(<<~KEY)
<YOUR PRIVATE KEY>
KEY

payload = {
  id: '{CUSTOMER_ID}',
  name: '{CUSTOMER_NAME}',
  iss: WORKSPACE_KEY,
  exp: Time.now.to_i + 60 * 60 * 6, # Expiration time (6 hours from now)
}

token = JWT.encode(payload, PRIVATE_KEY, 'ES256')
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.temporal.ChronoUnit;
import java.util.Base64;
import java.util.Date;

String workspaceKey = "<WORKSPACE_KEY>";

// Do not expose your private key to anyone. You should only use it to sign tokens.
String privateKeyPEM = "<YOUR PRIVATE KEY>";

String privateKeyContent = privateKeyPEM
    .replace("-----BEGIN PRIVATE KEY-----", "")
    .replace("-----END PRIVATE KEY-----", "")
    .replaceAll("\\s", "");

byte[] keyBytes = Base64.getDecoder().decode(privateKeyContent);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

String jwtToken = Jwts.builder()
        .claim("id", "{CUSTOMER_ID}") // Identifier of user or organization.
        .claim("name", "{CUSTOMER_NAME}") // Human-readable name (it will simplify troubleshooting)
        // .claim("fields", <user fields value>) (optional) Any user fields you want to attach to your user.
        .setExpiration(Date.from(new Date().toInstant().plus(14400, ChronoUnit.SECONDS))) // To prevent token from being used for too long
        .setIssuer(workspaceKey)
        .signWith(privateKey, SignatureAlgorithm.ES256)
        .setHeaderParam("typ", "JWT")
        .compact();
use Firebase\JWT\JWT;

// Your workspace key.
// You can find it on the Settings page.
$key = '<WORKSPACE_KEY>';

// Do not expose your private key to anyone. You should only use it to sign tokens.
$privateKey = <<<KEY
<YOUR PRIVATE KEY>
KEY;

$payload = [
    'id' => "{CUSTOMER_ID}",  // ID of your customer in your system. It will be used to identify customer in Membrane
    'name' => "{CUSTOMER_NAME}", // Human-readable customer name (it will simplify troubleshooting)
    'iss' => $key,
    'exp' => time() + 60 * 60 * 24 * 60, // To prevent token from being used for too long
];
$token = JWT::encode($payload, $privateKey, 'ES256');

Step 4: Admin Token

Admin tokens are used for administrative operations that affect user management, such as creating or editing users.

Admin tokens differ from regular tokens in two ways:

• You must include an isAdmin field with any non-empty value

• You should NOT include an id claim - admin tokens should not be attached to any user