PKCE Implementation
The SDK automatically implements PKCE (Proof Key for Code Exchange) to prevent authorization code interception attacks.
The Stack Overflow SDK provides built-in authentication helpers that simplify the OAuth 2.0 flow with PKCE for secure token generation. Authentication requirements vary by Stack Overflow for Teams tier.
The SDK includes two authentication clients for Enterprise instances:
import StackOverflowSDK from '@stackoverflow/teams-sdk';
// Option 1: OAuth configuration (no token required initially)const sdk = new StackOverflowSDK({ baseUrl: 'https://your-site.stackenterprise.co', auth: { clientId: 'your-client-id', redirectUri: 'https://yourapp.com/callback', baseUrl: 'https://your-site.stackenterprise.co', scope: 'read_inbox write_access' }});
// Option 2: With existing access tokenconst sdk = StackOverflowSDK.fromToken( 'your-access-token', 'https://your-site.stackenterprise.co');
// Option 3: Factory method for OAuth setupconst sdk = StackOverflowSDK.enterpriseOAuth({ clientId: 'your-client-id', redirectUri: 'https://yourapp.com/callback', baseUrl: 'https://your-site.stackenterprise.co'});import StackOverflowSDK from '@stackoverflow/teams-sdk';
// PAT is mandatory for Basic/Business tiersconst sdk = StackOverflowSDK.fromToken( 'your-personal-access-token', 'https://api.stackoverflowteams.com/v3');
// Team context is required for Basic/Business operationsconst teamContext = sdk.forTeam('your-team-id');const questions = await teamContext.questions.getAll();The BackendAuthClient handles the complete OAuth flow with PKCE on your server:
import { BackendAuthClient } from '@stackoverflow/teams-sdk';
const authClient = new BackendAuthClient({ clientId: 'your-client-id', redirectUri: 'https://yourapp.com/callback', baseUrl: 'https://your-site.stackenterprise.co', scope: 'read_inbox write_access' // Optional});
// Generate authorization URLconst { url, codeVerifier, state } = await authClient.getAuthUrl();
// Store codeVerifier and state securely (session, database, etc.)// Redirect user to the authorization URL
// In your callback handler:const tokens = await authClient.exchangeCodeForToken( callbackCode, storedCodeVerifier);
// Validate state for CSRF protectionconst isValidState = authClient.validateState(callbackState, storedState);The FrontendAuthClient communicates with your backend API to handle OAuth securely:
import { FrontendAuthClient } from '@stackoverflow/teams-sdk';
const frontendClient = new FrontendAuthClient({ clientId: 'your-client-id', redirectUri: 'https://yourapp.com/callback', baseUrl: 'https://your-site.stackenterprise.co'}, '/api'); // Your backend API base URL
// Start authentication flowconst authUrl = await frontendClient.startAuth();window.location.href = authUrl;
// Handle OAuth callbackawait frontendClient.handleCallback();
// Check authentication statusconst isAuthenticated = await frontendClient.getAuthStatus();
// Manual token submission (for PATs)const success = await frontendClient.submitAccessToken(userToken);interface AuthConfig { /** OAuth client ID from Stack Overflow Enterprise */ clientId: string; /** Redirect URI registered with your application */ redirectUri: string; /** Stack Overflow Enterprise instance URL */ baseUrl: string; /** OAuth scopes (optional) */ scope?: string;}| Method | Description | Returns |
|---|---|---|
generatePKCETokens() | Generate PKCE tokens for secure OAuth | Promise<PKCETokens> |
getAuthUrl() | Generate authorization URL with PKCE | Promise<{url, codeVerifier, state}> |
exchangeCodeForToken() | Exchange auth code for access token | Promise<TokenResponse> |
validateState() | Validate state parameter for CSRF protection | boolean |
| Method | Description | Returns |
|---|---|---|
startAuth() | Start OAuth flow via backend API | Promise<string> |
completeAuth() | Complete OAuth with callback params | Promise<void> |
handleCallback() | Handle OAuth callback in current page | Promise<void> |
getAuthStatus() | Check if user is authenticated | Promise<boolean> |
submitAccessToken() | Submit manual access token | Promise<boolean> |
logout() | Clear authentication state | Promise<boolean> |
Different API operations require different scopes:
| Scope | Description |
|---|---|
| read_inbox | Access user’s inbox |
| write_access | Perform write operations |
| private_info | Access private user data |
| no_expiry | Token never expires (use with caution) |
PKCE Implementation
The SDK automatically implements PKCE (Proof Key for Code Exchange) to prevent authorization code interception attacks.
State Validation
Always validate the state parameter in OAuth callbacks to prevent CSRF attacks using the built-in validation methods.
Secure Token Storage
Follow secure token storage best practices and avoid client-side storage for sensitive authentication data.
Environment Variables
Keep sensitive configuration like client IDs and secrets in environment variables, not in your source code.
Handle authentication errors gracefully:
async function authenticateUser() { try { const authUrl = await authClient.getAuthUrl(); // Handle success } catch (error) { if (error.message.includes('clientId')) { console.error('Missing OAuth configuration'); } else { console.error('Authentication setup failed:', error); } }}
// In callback handlertry { const tokens = await authClient.exchangeCodeForToken(code, codeVerifier);} catch (error) { if (error.message.includes('Failed to exchange')) { console.error('Token exchange failed - check OAuth configuration'); } throw error;}For simpler Enterprise implementations, you can generate Tokens manually and use them as seen below:
const sdk = StackOverflowSDK.fromToken( 'your-enterprise-pat', 'https://your-site.stackenterprise.co');
const questions = await sdk.questions.getAll();You’ll need to follow this guide to understand how OAuth works on Enterprise.
For Basic and Business tiers, PATs are the only authentication method available:
Personal Access Tokens (PATs) for API Authentication →
const sdk = StackOverflowSDK.fromToken(userProvidedPAT, 'https://api.stackoverflowteams.com/v3');const teamContext = sdk.forTeam('team-123');Once you have authentication configured with the helpers: