Skip to main content
Glama
auth-example.ts7.6 kB
/** * FreshBooks OAuth2 Authentication Example * * Demonstrates the complete OAuth2 flow for FreshBooks authentication. */ import { FreshBooksOAuth } from '../src/auth/oauth.js'; import { EncryptedFileTokenStore } from '../src/auth/token-store.js'; import { OAuthConfig } from '../src/auth/types.js'; import * as readline from 'readline'; /** * Example: Complete OAuth2 authentication flow */ async function authenticateExample() { console.log('FreshBooks OAuth2 Authentication Example\n'); // Step 1: Configure OAuth const config: OAuthConfig = { clientId: process.env.FRESHBOOKS_CLIENT_ID || '', clientSecret: process.env.FRESHBOOKS_CLIENT_SECRET || '', redirectUri: process.env.FRESHBOOKS_REDIRECT_URI || 'http://localhost:3000/callback', }; if (!config.clientId || !config.clientSecret) { console.error('Error: FRESHBOOKS_CLIENT_ID and FRESHBOOKS_CLIENT_SECRET must be set'); console.error('Set these in your .env file or environment variables'); process.exit(1); } // Step 2: Create OAuth client with encrypted token storage const tokenStore = new EncryptedFileTokenStore('./freshbooks-tokens.enc'); const oauth = new FreshBooksOAuth(config, tokenStore); // Step 3: Check if already authenticated const status = await oauth.getStatus(); if (status.authenticated) { console.log('Already authenticated!'); console.log(`Token expires in: ${status.expiresIn} seconds`); console.log(`Account ID: ${status.accountId || 'Not set'}`); console.log('\nYou can start using the API now.'); return; } console.log('Not authenticated. Starting OAuth flow...\n'); // Step 4: Generate authorization URL const state = Math.random().toString(36).substring(7); // Random state for CSRF protection const authUrl = oauth.generateAuthorizationUrl(state); console.log('Step 1: Visit this URL to authorize the application:'); console.log(authUrl); console.log(); // Step 5: Wait for user to complete authorization and get code const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); const authCode = await new Promise<string>((resolve) => { rl.question('Step 2: After authorizing, paste the authorization code here: ', (code) => { rl.close(); resolve(code.trim()); }); }); if (!authCode) { console.error('Error: No authorization code provided'); process.exit(1); } // Step 6: Exchange authorization code for tokens try { console.log('\nExchanging authorization code for tokens...'); const tokens = await oauth.exchangeCode(authCode); console.log('\nAuthentication successful!'); console.log(`Access token expires in: ${tokens.expiresAt - Math.floor(Date.now() / 1000)} seconds`); console.log('Tokens have been securely stored.'); console.log('\nYou can now use the API.'); // Step 7: Verify authentication const newStatus = await oauth.getStatus(); console.log('\nAuthentication status:'); console.log(`- Authenticated: ${newStatus.authenticated}`); console.log(`- Expires in: ${newStatus.expiresIn} seconds`); } catch (error: any) { console.error('\nAuthentication failed:'); console.error(`Error: ${error.message}`); if (error.code) { console.error(`Code: ${error.code}`); } process.exit(1); } } /** * Example: Using stored tokens */ async function useStoredTokensExample() { console.log('Using Stored Tokens Example\n'); const config: OAuthConfig = { clientId: process.env.FRESHBOOKS_CLIENT_ID || '', clientSecret: process.env.FRESHBOOKS_CLIENT_SECRET || '', redirectUri: process.env.FRESHBOOKS_REDIRECT_URI || 'http://localhost:3000/callback', }; const tokenStore = new EncryptedFileTokenStore('./freshbooks-tokens.enc'); const oauth = new FreshBooksOAuth(config, tokenStore); try { // Get valid token (automatically refreshes if needed) const accessToken = await oauth.getValidToken(); console.log('Got valid access token'); console.log('Token length:', accessToken.length); console.log('Token preview:', accessToken.substring(0, 20) + '...'); // Use token for API request console.log('\nMaking API request...'); const response = await fetch('https://api.freshbooks.com/auth/api/v1/users/me', { headers: { 'Authorization': `Bearer ${accessToken}`, 'Api-Version': 'alpha', 'Content-Type': 'application/json', }, }); if (response.ok) { const data = await response.json(); console.log('API request successful!'); console.log('User info:', JSON.stringify(data, null, 2)); } else { console.error('API request failed:', response.status, response.statusText); } } catch (error: any) { console.error('Error:', error.message); if (error.code === 'not_authenticated') { console.log('\nNot authenticated. Run the authentication example first.'); } } } /** * Example: Checking authentication status */ async function checkStatusExample() { console.log('Authentication Status Check Example\n'); const config: OAuthConfig = { clientId: process.env.FRESHBOOKS_CLIENT_ID || '', clientSecret: process.env.FRESHBOOKS_CLIENT_SECRET || '', redirectUri: process.env.FRESHBOOKS_REDIRECT_URI || 'http://localhost:3000/callback', }; const tokenStore = new EncryptedFileTokenStore('./freshbooks-tokens.enc'); const oauth = new FreshBooksOAuth(config, tokenStore); const status = await oauth.getStatus(); console.log('Authentication Status:'); console.log('- Authenticated:', status.authenticated); if (status.authenticated) { console.log('- Expires in:', status.expiresIn, 'seconds'); console.log('- Account ID:', status.accountId || 'Not set'); console.log('- Business ID:', status.businessId || 'Not set'); } else { console.log('- Reason:', status.reason); console.log('- Can refresh:', status.canRefresh || false); } } /** * Example: Revoking authentication */ async function revokeExample() { console.log('Revoke Authentication Example\n'); const config: OAuthConfig = { clientId: process.env.FRESHBOOKS_CLIENT_ID || '', clientSecret: process.env.FRESHBOOKS_CLIENT_SECRET || '', redirectUri: process.env.FRESHBOOKS_REDIRECT_URI || 'http://localhost:3000/callback', }; const tokenStore = new EncryptedFileTokenStore('./freshbooks-tokens.enc'); const oauth = new FreshBooksOAuth(config, tokenStore); console.log('Revoking authentication...'); await oauth.revokeToken(); console.log('Authentication revoked. Tokens cleared.'); const status = await oauth.getStatus(); console.log('\nNew status:'); console.log('- Authenticated:', status.authenticated); } // Main const example = process.argv[2] || 'authenticate'; switch (example) { case 'authenticate': authenticateExample().catch(console.error); break; case 'use-tokens': useStoredTokensExample().catch(console.error); break; case 'status': checkStatusExample().catch(console.error); break; case 'revoke': revokeExample().catch(console.error); break; default: console.log('Usage: npm run example:auth [authenticate|use-tokens|status|revoke]'); console.log(''); console.log('Examples:'); console.log(' npm run example:auth authenticate - Complete OAuth flow'); console.log(' npm run example:auth use-tokens - Use stored tokens'); console.log(' npm run example:auth status - Check auth status'); console.log(' npm run example:auth revoke - Revoke authentication'); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Good-Samaritan-Software-LLC/freshbooks-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server