Skip to main content

Auth Provider Integration

When a user launches your application through the General Wisdom marketplace, your app receives a signed JWT containing session claims. Your backend must exchange this JWT for credentials in your own identity provider so the user gets a seamless, authenticated experience within your application.

How JWT Exchange Works

sequenceDiagram
participant Marketplace as General Wisdom Marketplace
participant SDK as Provider SDK (your frontend)
participant Backend as Your Backend
participant IdP as Your Identity Provider

Marketplace->>SDK: Launch with ?gwSession=<JWT>
SDK->>SDK: Validate JWT signature (JWKS)
SDK->>Backend: POST /auth/exchange (Bearer JWT)
Backend->>Backend: Verify JWT claims (iss, applicationId, exp)
Backend->>IdP: Find or create user
IdP-->>Backend: User record
Backend->>IdP: Authenticate user (ROPC grant)
IdP-->>Backend: Access token + refresh token
Backend-->>SDK: Tokens + user info
SDK->>SDK: Store tokens, start session timer

JWT Claims Reference

Every marketplace JWT contains these claims:

ClaimTypeDescription
userIdstringUnique General Wisdom user identifier
orgIdstringOrganization the user belongs to
applicationIdstringYour registered application ID
sessionIdstringUnique session identifier
emailstringUser email address (when available)
expnumberToken expiration (Unix timestamp)
issstringIssuer (generalwisdom.com)
durationMinutesnumberSession duration in minutes

Provider Selection Guide

Choose your identity provider based on your existing infrastructure:

ProviderBest ForUser ManagementToken Format
KeycloakSelf-hosted, full control, open sourceAdmin REST APIJWT (realm_access roles)
Auth0Managed service, rapid setupManagement API v2JWT (namespaced claims)
OktaEnterprise SSO, workforce identityUsers API + SSWS tokensJWT (groups claim)
Microsoft Entra IDAzure ecosystem, Microsoft 365Microsoft Graph APIJWT (app roles)
AWS CognitoAWS-native, cost-effectiveAdmin APIs (SigV4)JWT (cognito:groups)

Common Exchange Pattern

Regardless of which provider you use, the backend exchange follows a consistent pattern:

async function exchangeMarketplaceToken(marketplaceJwt: string) {
// 1. Validate the marketplace JWT
const claims = await validateJWT(marketplaceJwt, {
issuer: 'generalwisdom.com',
jwksUri: 'https://api.generalwisdom.com/.well-known/jwks.json',
algorithms: ['RS256'],
});

// 2. Verify applicationId binding
if (claims.applicationId !== process.env.APPLICATION_ID) {
throw new Error('Token issued for different application');
}

// 3. Find or create user in your IdP
let user = await idp.findUser(claims.userId);
if (!user) {
user = await idp.createUser({
username: `gw-${claims.userId}`,
email: claims.email,
attributes: { gwUserId: claims.userId, orgId: claims.orgId },
});
}

// 4. Obtain tokens from your IdP
const tokens = await idp.authenticateUser(user);

return {
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token,
expiresIn: tokens.expires_in,
};
}

Security Requirements

All provider integrations must follow these security requirements:

  • Always validate the JWT signature using the JWKS endpoint before trusting any claims
  • Verify the applicationId claim matches your registered application
  • Check token expiration before processing the exchange
  • Use confidential clients with client secrets for all backend token exchanges
  • Never expose admin API credentials (API tokens, client secrets) to the frontend
  • Generate deterministic passwords derived from userId + clientSecret using SHA-256 -- never store raw passwords
  • Use HTTPS for all identity provider communication

SDK Integration

The Provider SDK handles the frontend portion of the exchange automatically via lifecycle hooks:

import MarketplaceSDK from '@mission_sciences/provider-sdk';

const sdk = new MarketplaceSDK({
apiKey: 'gwsk_...',
applicationId: 'your-app-id',
jwksUri: 'https://api.generalwisdom.com/.well-known/jwks.json',
hooks: {
onSessionStart: async (context) => {
// Exchange JWT for your IdP tokens
const tokens = await fetch('/auth/exchange', {
method: 'POST',
headers: { Authorization: `Bearer ${context.jwt}` },
}).then(r => r.json());

// Store tokens for your application
sessionStorage.setItem('access_token', tokens.accessToken);
},
onSessionEnd: async (context) => {
// Clean up tokens and revoke sessions
sessionStorage.clear();
await fetch('/auth/logout', { method: 'POST' });
},
},
});

await sdk.initialize();

Next Steps

Choose your provider guide to get started with a complete integration: