auth_exchange_code
Exchange OAuth authorization codes for secure access tokens to authenticate with FreshBooks accounting services.
Instructions
Exchange OAuth authorization code for access tokens
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Authorization code from OAuth redirect |
Implementation Reference
- src/server.ts:98-111 (registration)Registration of the 'auth_exchange_code' tool in the ListTools handler, including name, description, and input schema definition.{ name: 'auth_exchange_code', description: 'Exchange OAuth authorization code for access tokens', inputSchema: { type: 'object', properties: { code: { type: 'string', description: 'Authorization code from OAuth redirect', }, }, required: ['code'], }, },
- src/server.ts:227-256 (handler)MCP tool handler for 'auth_exchange_code': validates args.code, calls OAuth exchangeCode, updates client accountId, returns formatted success response with token info.private async handleAuthExchangeCode(args: any) { if (!args || !args.code) { throw createAuthError('Authorization code is required'); } const tokenData = await this.oauth.exchangeCode(args.code); // Set account if provided in token if (tokenData.accountId) { this.client.setAccountId(tokenData.accountId); } return { content: [ { type: 'text', text: JSON.stringify( { success: true, message: 'Authentication successful', accountId: tokenData.accountId, expiresIn: tokenData.expiresAt - Math.floor(Date.now() / 1000), }, null, 2 ), }, ], }; }
- src/auth/oauth.ts:95-138 (helper)Core OAuth logic for exchanging authorization code: HTTP POST to FreshBooks token endpoint with client credentials and code, handles response/errors, parses/saves tokens via TokenStore.async exchangeCode(code: string): Promise<TokenData> { try { const response = await fetch(FreshBooksOAuth.TOKEN_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Api-Version': 'alpha', }, body: JSON.stringify({ grant_type: 'authorization_code', client_id: this.config.clientId, client_secret: this.config.clientSecret, code, redirect_uri: this.config.redirectUri, }), }); if (!response.ok) { const error = await response.json() as OAuthErrorResponse; throw new OAuthError( this.mapErrorCode(error.error), error.error_description || 'Failed to exchange authorization code', error ); } const data = await response.json() as TokenResponse; const tokenData = this.parseTokenResponse(data); // Save tokens to store await this.tokenStore.save(tokenData); return tokenData; } catch (error) { if (error instanceof OAuthError) { throw error; } throw new OAuthError( 'token_exchange_failed', 'Failed to exchange authorization code', error ); } }