GitHub user FrancescoCastaldi added a comment to the discussion: Offline Pure
JWT Guest Token: Best practices for Secret generation, storage, and BFF vs
Superset responsibility
Here is the breakdown of best practices for the offline pure JWT guest token
architecture:
### 1. Role Division (BFF vs Superset)
Your proposed architecture is the recommended enterprise pattern.
- **BFF Responsibility:** Authenticates the portal user, evaluates business
rules (e.g., tenant ID, region, user permissions), selects the allowed
dashboard UUID, constructs Row Level Security (RLS) clauses, and signs the JWT.
- **Superset Responsibility:** Verifies the cryptographic signature against
`GUEST_TOKEN_JWT_SECRET`, checks expiration (`exp`), and applies the RLS
clauses to SQL queries executed on behalf of that guest session.
Never expose `GUEST_TOKEN_JWT_SECRET` to the Angular client. The browser must
only receive the signed guest token via the `fetchGuestToken` callback in
`@superset-ui/embedded-sdk`.
### 2. Payload Schema Distinction (`rls_rules` vs `rls`)
When calling Superset's REST endpoint (`POST /api/v1/security/guest_token/`),
the JSON payload uses the key `"rls"`. However, when minting the JWT offline in
your BFF, the JWT claims payload must use **`rls_rules`**.
Example Node.js BFF signing implementation:
```typescript
import jwt from 'jsonwebtoken';
function createGuestToken(user: { id: string; tenantId: string }, dashboardId:
string): string {
const secret = process.env.SUPERSET_GUEST_TOKEN_SECRET!;
const payload = {
user: {
username: `guest_${user.id}`,
first_name: 'Portal',
last_name: user.id,
},
resources: [
{
type: 'dashboard',
id: dashboardId,
},
],
rls_rules: [
{
clause: `tenant_id = '${user.tenantId.replace(/'/g, "''")}'`,
},
],
type: 'guest',
aud: 'superset',
};
return jwt.sign(payload, secret, {
algorithm: 'HS256',
expiresIn: '5m', // Short TTL; SDK automatically fetches a new token before
expiry
});
}
```
### 3. Secret Generation and Environment Isolation
- `openssl rand -hex 32` generates 256 bits of entropy (64 hex characters),
which is optimal for HS256.
- Treat the hex string as raw text. Ensure that both Node.js
(`process.env.SUPERSET_GUEST_TOKEN_SECRET`) and Superset
(`GUEST_TOKEN_JWT_SECRET = os.environ.get("...")`) receive the exact same
string value without decoding it into binary buffers on one side only.
- Each environment (QA, UAT, Production) must use an independent secret to
prevent token forgery across tiers.
### 4. Secret Storage and Rotation
Storing the secret in Azure Key Vault or AWS Secrets Manager and injecting it
as an environment variable into both the BFF and Superset containers is the
standard cloud architecture. When rotating secrets, coordinate deployment to
update both services simultaneously, or set a brief transition window during
scheduled maintenance.
GitHub link:
https://github.com/apache/superset/discussions/45444#discussioncomment-19164446
----
This is an automatically sent email for [email protected].
To unsubscribe, please send an email to:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]