Back to Participants

Third-Party Integration Guide

For external applications using OAuth 2.0

What is Third-Party Integration?

Third-Party Integration is for external applications and clients that are not part of the RegardingWork ecosystem. These integrations use the OAuth 2.0 Authorization Code Flow with PKCE for secure, standardized authentication.

Key Characteristics:
  • External domains - Not using *.regardingwork.com subdomains
  • OAuth 2.0 standard - Industry-standard authorization protocol
  • User consent - Users explicitly authorize access to their data
  • Scoped access - Applications request specific permissions
  • Secure flow - Authorization codes exchanged for tokens
Important: Third-party applications must be registered with RegardingWork Hub and approved before integration.
OAuth 2.0 Authorization Code Flow
1. User Authorization Request

Your app redirects user to Hub authorization endpoint.

2. User Consent

User reviews permissions and grants access to your app.

3. Authorization Code

Hub redirects back with authorization code.

4. Token Exchange

Your server exchanges code for access & refresh tokens.

5. API Access

Use access token to make authorized API calls.


sequenceDiagram
    participant User
    participant ThirdParty
    participant Hub
    
    User->>ThirdParty: Use App
    ThirdParty->>Hub: Authorization Request
    Hub->>User: Login & Consent Form
    User->>Hub: Grant Permission
    Hub->>ThirdParty: Authorization Code
    ThirdParty->>Hub: Exchange Code for Tokens
    Hub->>ThirdParty: Access & Refresh Tokens
    ThirdParty->>Hub: API Calls with Access Token
    Hub->>ThirdParty: User Data
                            
Application Registration
Prerequisites: Third-party applications must be registered before integration.
Registration Requirements:
  • Application Name - User-friendly name for your app
  • Application Description - What your app does
  • Redirect URIs - Authorized callback URLs
  • Scopes - Permissions your app needs
  • Contact Information - Developer contact details
Available Scopes:
Scope Description Access Level
profile:read Read user profile information Username, email, display name
teams:read Read user's team memberships Team names and user roles
teams:write Manage team memberships Add/remove team members
Contact: To register your application, contact RegardingWork support with your requirements.
Implementation Steps
Step 1 Generate PKCE Parameters

Create code verifier and challenge for security:


// Generate PKCE parameters
function generateCodeVerifier() {
    const array = new Uint8Array(32);
    crypto.getRandomValues(array);
    return btoa(String.fromCharCode.apply(null, array))
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');
}

function generateCodeChallenge(verifier) {
    const encoder = new TextEncoder();
    const data = encoder.encode(verifier);
    return crypto.subtle.digest('SHA-256', data).then(digest => {
        return btoa(String.fromCharCode.apply(null, new Uint8Array(digest)))
            .replace(/\+/g, '-')
            .replace(/\//g, '_')
            .replace(/=/g, '');
    });
}

// Store code verifier for later use
const codeVerifier = generateCodeVerifier();
sessionStorage.setItem('pkce_verifier', codeVerifier);
const codeChallenge = await generateCodeChallenge(codeVerifier);
                    
Step 2 Initiate Authorization

Redirect user to Hub's authorization endpoint:


// OAuth authorization request
function initiateOAuth() {
    const params = new URLSearchParams({
        client_id: 'your-registered-client-id',
        response_type: 'code',
        redirect_uri: 'https://your-app.com/oauth/callback',
        scope: 'profile:read teams:read',
        state: generateRandomState(), // CSRF protection
        code_challenge: codeChallenge,
        code_challenge_method: 'S256'
    });
    
    const authUrl = `https://hub.regardingwork.com/api/oauth/authorize?${params}`;
    window.location.href = authUrl;
}

function generateRandomState() {
    const array = new Uint8Array(16);
    crypto.getRandomValues(array);
    return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
}
                    
Step 3 Handle Authorization Callback

Process the authorization code from Hub:


// OAuth callback handler: /oauth/callback
app.get('/oauth/callback', async (req, res) => {
    const { code, state, error } = req.query;
    
    if (error) {
        return res.redirect(`/login?error=${error}`);
    }
    
    // Verify state parameter (CSRF protection)
    const expectedState = req.session.oauth_state;
    if (state !== expectedState) {
        return res.redirect('/login?error=invalid_state');
    }
    
    try {
        // Exchange authorization code for tokens
        const tokens = await exchangeCodeForTokens(code);
        
        // Store tokens securely
        req.session.access_token = tokens.access_token;
        req.session.refresh_token = tokens.refresh_token;
        
        res.redirect('/dashboard');
    } catch (error) {
        res.redirect('/login?error=token_exchange_failed');
    }
});
                    
Step 4 Exchange Code for Tokens

Server-side token exchange with PKCE:


// Token exchange function
async function exchangeCodeForTokens(authorizationCode) {
    const codeVerifier = sessionStorage.getItem('pkce_verifier');
    
    const response = await fetch('https://hub.regardingwork.com/api/oauth/token', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: new URLSearchParams({
            grant_type: 'authorization_code',
            client_id: 'your-registered-client-id',
            code: authorizationCode,
            redirect_uri: 'https://your-app.com/oauth/callback',
            code_verifier: codeVerifier
        })
    });
    
    if (!response.ok) {
        throw new Error('Token exchange failed');
    }
    
    return await response.json();
    // Returns: { access_token, refresh_token, token_type, expires_in }
}
                    
Step 5 Make Authorized API Calls

Use access tokens for API requests:


// Authorized API call example
async function getUserProfile(accessToken) {
    const response = await fetch('https://hub.regardingwork.com/api/auth/me', {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json'
        }
    });
    
    if (!response.ok) {
        if (response.status === 401) {
            // Token expired, refresh it
            return await refreshTokenAndRetry();
        }
        throw new Error('API call failed');
    }
    
    return await response.json();
}

// Token refresh example
async function refreshAccessToken(refreshToken) {
    const response = await fetch('https://hub.regardingwork.com/api/oauth/token', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: new URLSearchParams({
            grant_type: 'refresh_token',
            client_id: 'your-registered-client-id',
            refresh_token: refreshToken
        })
    });
    
    return await response.json();
}
                    
Security Best Practices
🔒 PKCE (Proof Key for Code Exchange)
  • Always use PKCE for public clients
  • Generate cryptographically secure code verifiers
  • Store code verifier securely on client
🛡️ State Parameter
  • Include state parameter for CSRF protection
  • Verify state matches on callback
  • Use cryptographically random values
🔐 Token Storage
  • Store tokens securely (httpOnly cookies)
  • Never expose tokens in client-side JavaScript
  • Implement proper token refresh logic
🌐 HTTPS Only
  • All OAuth flows must use HTTPS
  • Redirect URIs must be HTTPS
  • Never send tokens over HTTP
OAuth 2.0 API Endpoints
Endpoint Method Purpose Parameters
/api/oauth/authorize GET OAuth authorization client_id, redirect_uri, scope, state, code_challenge
/api/oauth/token POST Token exchange grant_type, code, code_verifier
/api/auth/me GET Get user profile Authorization: Bearer {token}
/api/user/teams GET Get user teams Authorization: Bearer {token}
Common Issues & Solutions

Problem: Your application isn't registered with Hub.
Solution: Register your application with RegardingWork Hub support and obtain a valid client_id.

Problem: Redirect URI doesn't match registered URIs.
Solution:
  • Ensure redirect URI exactly matches registration
  • Check for trailing slashes and case sensitivity
  • Verify HTTPS is used for production

Problem: Authorization code is expired or already used.
Solution:
  • Authorization codes expire in 10 minutes
  • Codes can only be used once
  • Ensure token exchange happens immediately after callback

Problem: PKCE code verifier doesn't match challenge.
Solution:
  • Ensure code verifier is stored securely between authorization and token exchange
  • Verify SHA256 hashing is implemented correctly
  • Check base64url encoding (no padding)
Related Documentation