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
Updated 2 days ago
