Onboarding a New Application to ZewstID
This guide covers the complete process of adding a new application to the ZewstID authentication system.
Overview
ZewstID supports two integration tracks:
| Track | For | Features |
|---|---|---|
| Track A | Internal Zewst apps (Zeye, ZPos, ZewstPay, etc.) | Full cross-portal SSO, custom login UI, all auth methods |
| Track B | Third-party / external apps | Standard OAuth/OIDC, no cross-portal SSO |
Who does what:
- ZewstID Admin (us): Configure authentication, create OAuth client, assign roles
- App Team (them): Install SDK, integrate authentication, implement RBAC
Timeline: ~1-2 hours for setup + integration time for app team
Determine the Integration Track
Track A: Internal Zewst Ecosystem Apps
Use Track A if:
- Application is a first-party Zewst product
- Needs cross-portal SSO (user logs into one app, automatically logged into all)
- Wants custom login UI with password, OTP, magic link support
- Will use the SDK with
@zewstid/nextjsenableSSOEstablishment: true
Examples: User Portal, Developer Portal, Admin Dashboard, Zeye, ZPos, ZewstPay
Track B: Third-Party / External Apps
Use Track B if:
- Application is built by external developers or partners
- Standard OAuth redirect flow is acceptable
- No need for cross-portal SSO with Zewst apps
- Can use any OAuth library (NextAuth, Passport, oidc-client-ts, etc.)
Examples: Partner integrations, customer apps, third-party tools
Part 0: Quick Reference by Track
Track A Setup (Internal Apps)
// app/api/zewstid/[...zewstid]/route.ts import { createZewstIDHandlers } from '@zewstid/nextjs/handlers'; const handlers = createZewstIDHandlers({ clientId: process.env.ZEWSTID_CLIENT_ID!, clientSecret: process.env.ZEWSTID_CLIENT_SECRET!, baseUrl: process.env.NEXTAUTH_URL, apiUrl: process.env.ZEWSTID_API_URL, issuerUrl: process.env.ZEWSTID_ISSUER_URL, enableSSOEstablishment: true, // Cross-portal SSO }); export const GET = handlers.GET; export const POST = handlers.POST;
Track B Setup (External Apps)
// app/api/auth/[...nextauth]/route.ts import NextAuth from 'next-auth'; export const authOptions = { providers: [ { id: 'zewstid', name: 'ZewstID', type: 'oidc', clientId: process.env.ZEWSTID_CLIENT_ID!, clientSecret: process.env.ZEWSTID_CLIENT_SECRET!, issuer: 'https://auth.zewstid.com/realms/zewstid', }, ], }; const handler = NextAuth(authOptions); export { handler as GET, handler as POST };
See OAuth Integration Guide for complete Track B examples with other frameworks.
Part 1: Admin Setup (ZewstID Team)
Step 1: Create OAuth Client
Use the ZewstID Admin Dashboard or API to create a new OAuth client:
# SSH to ZewstID server cd /opt/zewst-sso # Run client creation script ./scripts/create-oauth-client.sh
Provide:
- Client ID: (e.g.,
{app-name}-app,zeye-app,zpos-app)zewstpay-app - Client Name: (e.g.,
{App Name},Zeye,ZPos)ZewstPay - Root URL: (e.g.,
https://{app-domain}.zewst.com)https://zeye.zewst.com - Valid Redirect URIs:
https://{app-domain}.zewst.com/api/auth/callback/zewstid- (for dev)
http://localhost:3000/api/auth/callback/zewstid
Script creates:
- OAuth2 client with PKCE enabled
- Client secret (save this securely)
- Confidential access type
- Standard flow enabled
Alternative: Use the Admin Dashboard
- Go to https://admin.zewstid.com
- Navigate to Applications → Create New
- Fill in the client details
- Save and securely store the client secret
Alternative: Use the API
curl -X POST https://api.zewstid.com/v1/clients \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "clientId": "zeye-app", "name": "Zeye", "redirectUris": [ "https://zeye.zewst.com/api/auth/callback/zewstid", "http://localhost:3000/api/auth/callback/zewstid" ], "pkceEnabled": true }'
Step 2: Define Client Roles
Based on the application's needs, define roles:
# Example: Zeye roles zeye-admin # Full admin access zeye-user # Standard user (can view/manage cameras) zeye-viewer # Read-only access # Example: ZPos roles zpos-admin # Full admin access zpos-manager # Manager access (reports, inventory) zpos-cashier # Cashier access (transactions only)
Create roles via API:
# Create zeye-admin role curl -X POST https://api.zewstid.com/v1/roles \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "zeye-admin", "description": "Zeye Administrator", "clientId": "zeye-app", "permissions": ["zeye.*"] }' # Create zeye-user role curl -X POST https://api.zewstid.com/v1/roles \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "zeye-user", "description": "Zeye Standard User", "clientId": "zeye-app", "permissions": ["zeye.cameras.view", "zeye.cameras.manage"] }' # Create zeye-viewer role curl -X POST https://api.zewstid.com/v1/roles \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "zeye-viewer", "description": "Zeye Viewer (Read-only)", "clientId": "zeye-app", "permissions": ["zeye.cameras.view"] }'
Or use Admin Dashboard:
- Go to https://admin.zewstid.com
- Navigate to Roles → Create New
- Select client:
zeye-app - Add each role with appropriate permissions
Step 3: Configure Token Claims (Optional but Recommended)
Custom claims are automatically included in JWT tokens for client-specific roles. The SDK handles this automatically.
Default token structure:
{ "sub": "user-id", "email": "user@example.com", "client_roles": { "zeye-app": ["zeye-user"] }, "permissions": ["zeye.cameras.view", "zeye.cameras.manage"] }
Step 4: Create Test Users
Create users for the app team to test with:
./scripts/create-test-users.sh zeye-app
This creates:
- /
{app}-admin-user(with admin role)password - /
{app}-standard-user(with standard user role)password - /
{app}-viewer-user(with viewer role)password
Or create via API:
# Create admin user curl -X POST https://api.zewstid.com/v1/users \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "email": "zeye-admin@test.com", "password": "password", "emailVerified": true, "roles": { "zeye-app": ["zeye-admin"] } }'
Or use Admin Dashboard:
- Go to Users → Create New
- Fill in user details
- Navigate to Role Assignments
- Assign appropriate client roles
Step 5: Generate Integration Package
Prepare the handoff package for the app team:
# Get client secret via API CLIENT_SECRET=$(curl -X GET https://api.zewstid.com/v1/clients/zeye-app/secret \ -H "Authorization: Bearer $ADMIN_TOKEN" | jq -r '.secret') # Save to secure location echo "Client ID: zeye-app" > /secure/handoff-zeye.txt echo "Client Secret: $CLIENT_SECRET" >> /secure/handoff-zeye.txt
Part 2: Information to Share with App Team
Create a handoff document with:
2.1 Credentials & Configuration
# ZewstID Configuration for {App Name} # OAuth Configuration ZEWSTID_ISSUER_URL=https://auth.zewstid.com/realms/zewstid ZEWSTID_CLIENT_ID={app-name}-app ZEWSTID_CLIENT_SECRET={generated-secret} # NextAuth Configuration (for Next.js apps) NEXTAUTH_URL=https://{app-domain}.zewst.com NEXTAUTH_SECRET={generate-with: openssl rand -base64 32} # npm Registry (for @zewstid packages) NPM_REGISTRY=https://npm.zewstid.com/
2.2 Available Roles
| Role | Description | Typical Use Case |
|---|---|---|
{app}-admin | Full administrator access | System configuration, user management |
{app}-user | Standard user access | Normal application usage |
{app}-viewer | Read-only access | Viewing data only |
2.3 Test User Credentials
Admin User: Email: {app}-admin@test.com Password: password Roles: {app}-admin Standard User: Email: {app}-user@test.com Password: password Roles: {app}-user Viewer: Email: {app}-viewer@test.com Password: password Roles: {app}-viewer
2.4 SDK Information
# Install ZewstID SDK npm login --registry=https://npm.zewstid.com/ # (credentials provided separately) npm install @zewstid/nextjs
2.5 Key Endpoints
Authorization: https://auth.zewstid.com/realms/zewstid/protocol/openid-connect/auth Token: https://auth.zewstid.com/realms/zewstid/protocol/openid-connect/token UserInfo: https://auth.zewstid.com/realms/zewstid/protocol/openid-connect/userinfo JWKS: https://auth.zewstid.com/realms/zewstid/protocol/openid-connect/certs Logout: https://auth.zewstid.com/realms/zewstid/protocol/openid-connect/logout
Part 3: Developer Integration Guide (Share This)
The app team should follow the Quick Start Guide for step-by-step integration instructions.
This includes:
- Step-by-step SDK installation
- Authentication setup code
- RBAC implementation examples
- Route protection examples
- API route protection examples
- Testing instructions
Part 4: Admin Checklist
Use this checklist when onboarding a new app:
Pre-Onboarding
- Get app details from team (name, domain, required roles)
- Understand their user access patterns
- Confirm development and production URLs
OAuth Client Configuration
- Create OAuth2 client in ZewstID
- Configure redirect URIs (prod + dev)
- Generate and securely store client secret
- Create client roles based on requirements
- Verify token claims configuration
- Create test users with appropriate roles
- Test authentication flow with test users
Documentation & Handoff
- Create handoff document with credentials
- Share test user credentials
- Provide npm registry access
- Share developer integration guide
- Schedule kickoff call with app team
- Add to monitoring/logging
Post-Integration Support
- Verify first successful authentication
- Check token claims are correct
- Validate RBAC is working
- Set up production users
- Document in internal wiki
Part 5: Troubleshooting Common Issues
Issue: "Invalid redirect_uri"
Cause: Redirect URI not whitelisted in client configuration Fix: Add URI to Valid Redirect URIs in Admin Dashboard or via API
curl -X PATCH https://api.zewstid.com/v1/clients/zeye-app \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "redirectUris": [ "https://zeye.zewst.com/api/auth/callback/zewstid", "http://localhost:3000/api/auth/callback/zewstid" ] }'
Issue: "Roles not appearing in token"
Cause: User doesn't have roles assigned Fix:
- Check role assignments in Admin Dashboard
- Verify user has client roles assigned
# Assign role to user via API curl -X POST https://api.zewstid.com/v1/users/{user-id}/roles \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "clientId": "zeye-app", "roles": ["zeye-user"] }'
Issue: "401 Unauthorized" in production
Cause: Wrong client secret or environment variables Fix: Verify
ZEWSTID_CLIENT_SECRET# Retrieve client secret curl -X GET https://api.zewstid.com/v1/clients/zeye-app/secret \ -H "Authorization: Bearer $ADMIN_TOKEN"
Issue: "Cannot access private npm packages"
Cause: Not authenticated to Verdaccio Fix: Run
npm login --registry=https://npm.zewstid.com/Part 6: Security Best Practices
For Admin (Us)
- Client Secrets: Store in password manager, never commit to git
- Test Users: Use only in dev/staging, delete or disable in production
- Role Permissions: Follow principle of least privilege
- Token Expiry: Default is 5 minutes (access) + 30 minutes (refresh)
- Audit Logs: Monitor authentication events in Admin Dashboard
For App Team (Them)
- Environment Variables: Never commit secrets to git
- HTTPS Only: Always use HTTPS in production
- Token Storage: Use httpOnly cookies (SDK handles this)
- RBAC Checks: Always check on backend, not just frontend
- Session Management: Implement proper logout
Quick Reference Commands
# Create new client ./scripts/create-oauth-client.sh # Create test users for client ./scripts/create-test-users.sh {client-id} # Get client secret ./scripts/get-client-secret.sh {client-id} # List all clients via API curl -X GET https://api.zewstid.com/v1/clients \ -H "Authorization: Bearer $ADMIN_TOKEN" # View client roles curl -X GET https://api.zewstid.com/v1/clients/{client-id}/roles \ -H "Authorization: Bearer $ADMIN_TOKEN" # Assign role to user curl -X POST https://api.zewstid.com/v1/users/{user-id}/roles \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "clientId": "{client-id}", "roles": ["{role-name}"] }'
Support & Resources
- Admin Dashboard: https://admin.zewstid.com
- Developer Portal: https://developers.zewstid.com
- API Documentation: https://developers.zewstid.com/docs/api/reference
- Internal Docs: (link to internal wiki)
- Slack Channel: #zewstid-support
Example: Complete Zeye Onboarding
This is a real example showing exactly what was done for Zeye:
1. Admin Created Client
./scripts/create-oauth-client.sh # Input: # - Client ID: zeye-app # - Client Name: Zeye # - Root URL: https://zeye.zewst.com # - Redirect URIs: https://zeye.zewst.com/api/auth/callback/zewstid
2. Created Roles
- - Full admin access
zeye-admin - - Camera management
zeye-user - - Read-only
zeye-viewer
3. Created Test Users
- /
zeye-admin@test.compassword - /
zeye-user@test.compassword - /
zeye-viewer@test.compassword
4. Shared with Zeye Team
ZEWSTID_ISSUER_URL=https://auth.zewstid.com/realms/zewstid ZEWSTID_CLIENT_ID=zeye-app ZEWSTID_CLIENT_SECRET=abc123...
Plus developer integration guide with code examples.
5. Zeye Team Integration
- Installed
@zewstid/nextjs@0.7.3 - Configured authentication with ZewstID provider +
enableSSOEstablishment: true - Implemented RBAC with role permissions
- Protected routes with middleware
- Added role checks in UI components
Result: Fully integrated authentication with cross-portal SSO in ~4 hours
Next Steps
For Track A (Internal Apps)
- 5-Minute Quick Start - Get started fast
- API Handlers Guide - All SDK handlers
- RBAC Guide - Implementing role-based access control
- SDK Documentation - Full SDK API reference
For Track B (External Apps)
- OAuth Integration Guide - Standard OAuth/OIDC integration
- Quick Start Guide - Complete integration guide
- SDK Documentation - Full SDK API reference
Was this page helpful?
Let us know how we can improve our documentation