curl --request GET \
--url https://charts.basedash.com/api/sso/jwtimport requests
url = "https://charts.basedash.com/api/sso/jwt"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://charts.basedash.com/api/sso/jwt', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://charts.basedash.com/api/sso/jwt",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://charts.basedash.com/api/sso/jwt"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://charts.basedash.com/api/sso/jwt")
.asString();require 'uri'
require 'net/http'
url = URI("https://charts.basedash.com/api/sso/jwt")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body<string><string><string><string><string><string>JWT authentication
Validates a JWT signed by the embedding application and creates a Basedash session for the user specified in the JWT claims. On success, redirects to the organization dashboard.
curl --request GET \
--url https://charts.basedash.com/api/sso/jwtimport requests
url = "https://charts.basedash.com/api/sso/jwt"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://charts.basedash.com/api/sso/jwt', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://charts.basedash.com/api/sso/jwt",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://charts.basedash.com/api/sso/jwt"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://charts.basedash.com/api/sso/jwt")
.asString();require 'uri'
require 'net/http'
url = URI("https://charts.basedash.com/api/sso/jwt")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body<string><string><string><string><string><string>When to use
This endpoint is used for full app embedding - embedding the entire Basedash application within your own product via an iframe. This allows your users to access Basedash dashboards without leaving your application or managing separate Basedash credentials.How it works
- Your server generates a JWT containing user information, signed with your organization’s embed JWT secret
- You set the iframe
srcto this endpoint with the JWT as a query parameter - Basedash validates the JWT signature against your organization’s secret
- If valid, Basedash creates or updates the user account and establishes a session restricted to that organization
- The user is redirected to your organization’s dashboard inside the iframe
Setup requirements
Before using this endpoint, you must:- Enable embedding for your organization via the API or Basedash settings
- Store the embed JWT secret returned when creating/updating your organization - this is used to sign your JWTs
- Configure allowed origins (recommended) to restrict which domains can embed your Basedash organization
JWT structure
Sign your JWT using the HS256 algorithm with your organization’sjwtSecret. The JWT payload should contain:
{
"email": "user@example.com",
"orgId": "org_abc123",
"firstName": "Jane",
"lastName": "Doe",
"role": "MEMBER",
"groups": ["Billing", "Program A"],
"exp": 1234567890,
"iat": 1234567800
}
role claim accepts ADMIN, MEMBER, or VIEWER.
When supplied, it is the source of truth for the active membership on every
login. Omit it to preserve an active membership’s role; new or reactivated
memberships without a role claim default to MEMBER. VIEWER is read-only.
Groups
The optionalgroups claim lists the names of existing Basedash groups the
user belongs to. Use it to scope dashboards, chats, data sources and row-level
security to groups you manage from your application. When supplied, it is
applied on every login:
| Situation | Result |
|---|---|
| A name matches a group the user isn’t in | The user is added to the group |
| The claim no longer names a group this claim added the user to | The user is removed from that group |
| The user was added to a group in Basedash, through the API or by SCIM | Never removed by the claim |
groups is [] | Removes every membership the claim added |
groups is omitted | Group memberships are left unchanged |
- Names match case-insensitively, ignoring leading and trailing spaces.
- Groups are never created. Create them first with
POST /organizations/{orgId}/groups, and give them access before users log in. - A name that matches no group, matches more than one group, or names a
SCIM-managed group is skipped. So is the whole claim when it lists more than
100 distinct names. The login still succeeds. Each login that changes
memberships or skips a name records a
group.login_token_syncedaudit event listing the groups added and removed and every skipped name with its reason (unknown,ambiguous,scim_managedorinvalid_name). - Audit logs require the Enterprise plan. On Enterprise, find these events
under Settings → Audit logs, or query them with an administrator API key:
GET /organizations/{orgId}/audit-logs?action=group.login_token_synced. On other plans, compare the names you send withGET /organizations/{orgId}/groups. - If an admin removes a membership the claim added, the next login adds it back. To revoke access, remove the group from the claim. To revoke it immediately as well, also remove the membership in Basedash or through the API.
- On data sources with row-level security, group names are passed to your policies, so adding a group can widen the data a user sees.
Example implementation
<iframe
src="https://charts.basedash.com/api/sso/jwt?jwt=YOUR_JWT_TOKEN"
width="100%"
height="600"
frameborder="0"
/>
// Server-side JWT generation (Node.js example)
import jwt from 'jsonwebtoken';
const token = jwt.sign(
{
email: user.email,
orgId: 'org_abc123',
firstName: user.firstName,
lastName: user.lastName,
role: 'MEMBER',
groups: ['Billing', 'Program A'],
},
process.env.BASEDASH_EMBED_JWT_SECRET,
{ expiresIn: '10m' }
);
Customizing the embed
Append any of these query parameters to the iframe URL. They are forwarded through the redirect. Appearance and features apply for the rest of the iframe session, so later in-app navigation keeps them:| Parameter | Values | Effect |
|---|---|---|
theme | light, dark, auto | Override the theme |
hide_org_name | true, false | Hide the organization name in the sidebar |
hide_chat | true, false | Hide the Chat page and chat panel |
hide_dashboards | true, false | Hide dashboards |
hide_insights | true, false | Hide insights |
hide_automations | true, false | Hide automations |
hide_models | true, false | Hide models |
hide_suggested_prompts | true, false | Hide suggested prompts in the chat input |
hide_sidebar | true, false | Don’t render the left sidebar at all, with no way to reopen it |
hide_sidebar=true your application owns navigation. Breadcrumbs and search remain, but lists that only live in the sidebar (all dashboards and folders, chat history) are not shown, so pair it with a single visible feature and, for dashboards, an initial page. Hiding the sidebar is presentation only, not access control: use Basedash permissions to restrict what a user can open.
Initial page parameters choose the page the embed opens on. Set at most one:
| Parameter | Opens |
|---|---|
dashboard_id | A dashboard (combine with tab to open a dashboard tab) |
automation_id | An automation |
insight_id | An insight |
model_id | A model |
chat_id | A chat |
<iframe
src="https://charts.basedash.com/api/sso/jwt?jwt=YOUR_JWT_TOKEN&hide_chat=true&hide_insights=true&hide_automations=true&hide_models=true&hide_sidebar=true&dashboard_id=DASHBOARD_ID"
/>
Security considerations
- Keep your JWT secret secure - Never expose it in client-side code
- Use short expiration times - JWTs should expire within minutes
- Configure allowed origins - Restrict embedding to your domains only
- Organization-scoped access - JWT sessions cannot access the user’s other Basedash organizations
- Generate JWTs server-side - Never generate JWTs in the browser
Query Parameters
JWT token signed with your organization embed secret (HS256)
Override the theme
light, dark, auto Hide the organization name in the sidebar. Persists for the iframe session.
true, false Hide the Chat page and chat panel. Persists for the iframe session.
true, false Hide dashboards. Persists for the iframe session.
true, false Hide insights. Persists for the iframe session.
true, false Hide automations. Persists for the iframe session.
true, false Hide models. Persists for the iframe session.
true, false Hide suggested prompts in the chat input. Persists for the iframe session.
true, false Do not render the left sidebar, with no way to reopen it. Persists for the iframe session.
true, false Open the embed on this dashboard
With dashboard_id, the dashboard tab to open
Open the embed on this automation
Open the embed on this insight
Open the embed on this model
Open the embed on this chat
Response
Redirect to organization dashboard on successful authentication