DoneIsBetter SSO Integration Guide
API Version: 5.5.0
OAuth 2.0 Authorization Server
⚠️ Important: OAuth 2.0 Flow
This SSO service uses OAuth 2.0 Authorization Code Flow. The old client-side approach has been deprecated. You must implement server-side token exchange and handle app-level permissions.
Overview
DoneIsBetter SSO is an OAuth 2.0 authorization server that provides:
- Centralized Authentication - Users log in once, access multiple apps
- App-Level Permissions - Control which users can access which applications
- Role-Based Access - Assign users as
user
oradmin
per app - Admin Approval Workflow - New users require SSO admin approval before accessing apps
- Secure Token Management - JWT-based access and refresh tokens
Authentication Flow
User Clicks "Login"
Your app redirects to SSO authorization endpoint:
https://sso.doneisbetter.com/api/oauth/authorize? client_id=YOUR_CLIENT_ID& redirect_uri=https://yourapp.com/auth/callback& response_type=code& scope=openid profile email
User Authenticates
SSO presents login page. User enters credentials or uses magic link/PIN.
Permission Check
SSO verifies user has approved access to your app:
status: 'approved'
→ Continue to step 4status: 'pending'
→ Show "Access Pending Approval" messagestatus: 'revoked'
or no permission → Show "Access Denied"
Authorization Code
SSO redirects back to your app with authorization code:
https://yourapp.com/auth/callback?code=AUTHORIZATION_CODE
Token Exchange (Server-Side)
Your backend exchanges code for tokens:
POST https://sso.doneisbetter.com/api/oauth/token Content-Type: application/json { "grant_type": "authorization_code", "code": "AUTHORIZATION_CODE", "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "redirect_uri": "https://yourapp.com/auth/callback" }
Receive Tokens
SSO returns access token, ID token, and refresh token:
{ "access_token": "eyJhbGci...", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "eyJhbGci...", "id_token": "eyJhbGci..." }
Decode ID token to get user info and app-level role:
{ "sub": "user-uuid", "email": "user@example.com", "name": "User Name", "role": "admin", // App-level role: 'user' or 'admin' "iat": 1234567890, "exp": 1234571490 }
Integration Steps
Register Your Domain
Contact us at support@doneisbetter.com to register your domain.
Required information:
- Your domain name
- Organization name
- Technical contact email
- Development and production URLs
Add SSO Client
Include our client script in your HTML:
<script src="https://sso.doneisbetter.com/sso-client.js"></script>
Initialize SSO
Create an SSO instance and check authentication:
const sso = new SSOClient('https://sso.doneisbetter.com'); // Check on page load document.addEventListener('DOMContentLoaded', async () => { const session = await sso.validateSession(); if (session.isValid) { // Handle authenticated user console.log('User:', session.user); } else { // Handle unauthenticated state sso.redirectToLogin(); } });
API Reference
Session Validation
Endpoint: GET https://sso.doneisbetter.com/api/sso/validate
Headers:
Content-Type: application/json
Origin: your-domain.com
Success Response (200 OK)
{ "isValid": true, "user": { "id": "user_id", "username": "username", "permissions": { "isAdmin": false, "canViewUsers": false, "canManageUsers": false } }, "session": { "expiresAt": "2025-07-21T14:43:47Z" } }
Error Responses
401
- Invalid or expired session403
- Unauthorized domain500
- Server error
Security Best Practices
- Always use HTTPS in production
- Validate session status before accessing protected resources
- Implement proper error handling
- Don't store sensitive user data in localStorage
- Keep the SSO client script updated to the latest version
Example Implementations
React
import { useEffect, useState } from 'react'; function App() { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { async function checkAuth() { const sso = new SSOClient('https://sso.doneisbetter.com'); try { const result = await sso.validateSession(); if (result.isValid) { setUser(result.user); } else { sso.redirectToLogin(); } } catch (error) { console.error('Auth error:', error); } finally { setLoading(false); } } checkAuth(); }, []); if (loading) return <div>Loading...</div>; if (!user) return null; return <div>Welcome, {user.username}!</div>; }
Vue.js
// auth.js export default { data() { return { user: null, loading: true } }, async created() { const sso = new SSOClient('https://sso.doneisbetter.com'); try { const result = await sso.validateSession(); if (result.isValid) { this.user = result.user; } else { sso.redirectToLogin(); } } catch (error) { console.error('Auth error:', error); } finally { this.loading = false; } } }
Support
For technical support or to report issues:
- Email: support@doneisbetter.com
- Documentation: https://sso.doneisbetter.com/docs
- GitHub: https://github.com/doneisbetter/sso