| 
1 | 1 | ---  | 
2 | 2 | title: Authentication  | 
3 |  | -description: Learn how to authenticate with the Stack Overflow API to use the SDK.  | 
 | 3 | +description: Learn how to authenticate with the Stack Overflow API using the built-in authentication helpers.  | 
4 | 4 | ---  | 
5 | 5 | import { Card, CardGrid } from '@astrojs/starlight/components';  | 
6 | 6 | 
 
  | 
7 |  | -The Stack Overflow SDK requires an access token to authenticate API requests. This guide explains how to obtain and use access tokens with the SDK.  | 
 | 7 | +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.  | 
8 | 8 | 
 
  | 
9 |  | -## Overview  | 
 | 9 | +### Authentication by Tier  | 
10 | 10 | 
 
  | 
11 |  | -The SDK uses OAuth 2.0 with access tokens for authentication. All API calls require a valid access token to be passed during SDK initialization.  | 
 | 11 | +- **Stack Overflow for Teams Enterprise** - Supports OAuth 2.0 with PKCE. Access tokens can be generated dynamically. You can optionally provide a single Access Token manually.  | 
 | 12 | +- **Stack Overflow for Teams Basic/Business** - OAuth is not available. Manual input of Access tokens (PATs) are **required** in order to use the SDK.  | 
12 | 13 | 
 
  | 
 | 14 | +### Authentication Clients  | 
 | 15 | + | 
 | 16 | +The SDK includes two authentication clients for Enterprise instances:  | 
 | 17 | +- **BackendAuthClient** - For server-side Node.js environments with full PKCE implementation  | 
 | 18 | +- **FrontendAuthClient** - For browser environments that communicate with your backend API  | 
 | 19 | + | 
 | 20 | +### SDK Initialization Options  | 
 | 21 | + | 
 | 22 | +#### Enterprise - With OAuth Setup  | 
13 | 23 | ```typescript  | 
14 |  | -import StackOverflowSDK from 'so-teams-sdk;  | 
 | 24 | +import StackOverflowSDK from 'so-teams-sdk';  | 
15 | 25 | 
 
  | 
 | 26 | +// Option 1: OAuth configuration (no token required initially)  | 
16 | 27 | const sdk = new StackOverflowSDK({  | 
17 |  | -  baseUrl: 'https://[your-site].stackenterprise.co',  | 
18 |  | -  accessToken: 'your-access-token-here'  | 
 | 28 | +  baseUrl: 'https://your-site.stackenterprise.co',  | 
 | 29 | +  auth: {  | 
 | 30 | +    clientId: 'your-client-id',  | 
 | 31 | +    redirectUri: 'https://yourapp.com/callback',  | 
 | 32 | +    baseUrl: 'https://your-site.stackenterprise.co',  | 
 | 33 | +    scope: 'read_inbox write_access'  | 
 | 34 | +  }  | 
19 | 35 | });  | 
20 |  | -```  | 
21 | 36 | 
 
  | 
22 |  | -## Obtaining Access Tokens  | 
 | 37 | +// Option 2: With existing access token  | 
 | 38 | +const sdk = StackOverflowSDK.fromToken(  | 
 | 39 | +  'your-access-token',   | 
 | 40 | +  'https://your-site.stackenterprise.co'  | 
 | 41 | +);  | 
 | 42 | + | 
 | 43 | +// Option 3: Factory method for OAuth setup  | 
 | 44 | +const sdk = StackOverflowSDK.enterpriseOAuth({  | 
 | 45 | +  clientId: 'your-client-id',  | 
 | 46 | +  redirectUri: 'https://yourapp.com/callback',  | 
 | 47 | +  baseUrl: 'https://your-site.stackenterprise.co'  | 
 | 48 | +});  | 
 | 49 | +```  | 
23 | 50 | 
 
  | 
24 |  | -### For Stack Overflow for Teams Enterprise  | 
 | 51 | +#### Basic/Business - Personal Access Token Required  | 
 | 52 | +```typescript  | 
 | 53 | +import StackOverflowSDK from 'so-teams-sdk';  | 
25 | 54 | 
 
  | 
26 |  | -If you're using Stack Overflow for Teams Enterprise, follow the comprehensive OAuth implementation guide to generate secure API tokens:  | 
 | 55 | +// PAT is mandatory for Basic/Business tiers  | 
 | 56 | +const sdk = StackOverflowSDK.fromToken(  | 
 | 57 | +  'your-personal-access-token',  | 
 | 58 | +  'https://api.stackoverflowteams.com/v3'  | 
 | 59 | +);  | 
27 | 60 | 
 
  | 
28 |  | -**[Secure API Token Generation with OAuth and PKCE →](https://stackoverflow.help/en/articles/19820283-secure-api-token-generation-with-oauth-and-pkce)**  | 
 | 61 | +// Team context is required for Basic/Business operations  | 
 | 62 | +const teamContext = sdk.forTeam('your-team-id');  | 
 | 63 | +const questions = await teamContext.questions.getAll();  | 
 | 64 | +```  | 
29 | 65 | 
 
  | 
30 |  | -This guide covers:  | 
31 |  | -- OAuth Authorization Code flow  | 
32 |  | -- PKCE (Proof Key for Code Exchange) implementation  | 
33 |  | -- Token generation and management  | 
34 |  | -- Security best practices  | 
 | 66 | +## Authentication Clients (Enterprise Only)  | 
35 | 67 | 
 
  | 
36 |  | -### For Stack Overflow for Teams  | 
 | 68 | +:::note[Enterprise Feature]  | 
 | 69 | +Authentication clients are only available for Stack Overflow for Teams Enterprise instances. Basic/Business tiers must use Personal Access Tokens during SDK initialization.  | 
 | 70 | +:::  | 
37 | 71 | 
 
  | 
38 |  | -If you're using Stack Overflow for Teams (Business or Basic), the process is simpler. You can generate a Personal Access Token (PAT) by following this guide:  | 
 | 72 | +### Backend Authentication (Server-Side)  | 
39 | 73 | 
 
  | 
40 |  | -**[Personal Access Tokens (PATs) for API Authentication →](https://stackoverflowteams.help/en/articles/10908790-personal-access-tokens-pats-for-api-authentication)**  | 
 | 74 | +The `BackendAuthClient` handles the complete OAuth flow with PKCE on your server:  | 
41 | 75 | 
 
  | 
42 |  | -PATs allow you to authenticate securely with the API without needing the full OAuth flow.  | 
 | 76 | +```typescript title="backend-auth.ts"  | 
 | 77 | +import { BackendAuthClient } from 'so-teams-sdk';  | 
43 | 78 | 
 
  | 
44 |  | -## Using Access Tokens  | 
 | 79 | +const authClient = new BackendAuthClient({  | 
 | 80 | +  clientId: 'your-client-id',  | 
 | 81 | +  redirectUri: 'https://yourapp.com/callback',  | 
 | 82 | +  baseUrl: 'https://your-site.stackenterprise.co',  | 
 | 83 | +  scope: 'read_inbox write_access' // Optional  | 
 | 84 | +});  | 
45 | 85 | 
 
  | 
46 |  | -Once you have an access token, initialize the SDK with your credentials:  | 
 | 86 | +// Generate authorization URL  | 
 | 87 | +const { url, codeVerifier, state } = await authClient.getAuthUrl();  | 
47 | 88 | 
 
  | 
48 |  | -```typescript title="sdk-setup.ts"  | 
49 |  | -import StackOverflowSDK from 'so-teams-sdk;  | 
 | 89 | +// Store codeVerifier and state securely (session, database, etc.)  | 
 | 90 | +// Redirect user to the authorization URL  | 
50 | 91 | 
 
  | 
51 |  | -// For Stack Overflow for Teams  | 
52 |  | -const teamsSDK = new StackOverflowSDK({  | 
53 |  | -  baseUrl: 'https://your-site.stackenterprise.co',  | 
54 |  | -  accessToken: 'your-access-token'  | 
55 |  | -});  | 
 | 92 | +// In your callback handler:  | 
 | 93 | +const tokens = await authClient.exchangeCodeForToken(  | 
 | 94 | +  callbackCode,   | 
 | 95 | +  storedCodeVerifier  | 
 | 96 | +);  | 
56 | 97 | 
 
  | 
 | 98 | +// Validate state for CSRF protection  | 
 | 99 | +const isValidState = authClient.validateState(callbackState, storedState);  | 
57 | 100 | ```  | 
58 | 101 | 
 
  | 
59 |  | -## Token Scopes  | 
 | 102 | +### Frontend Authentication (Browser)  | 
60 | 103 | 
 
  | 
61 |  | -Different API operations require different scopes. Common scopes include:  | 
 | 104 | +The `FrontendAuthClient` communicates with your backend API to handle OAuth securely:  | 
62 | 105 | 
 
  | 
63 |  | -| Scope | Description |  | 
64 |  | -|-------|-------------|  | 
65 |  | -| read_inbox | Access user's inbox |  | 
66 |  | -| write_access | Perform write operations |  | 
67 |  | -| private_info | Access private user data |  | 
68 |  | -| no_expiry | Token never expires (use with caution) |  | 
 | 106 | +```typescript title="frontend-auth.ts"  | 
 | 107 | +import { FrontendAuthClient } from 'so-teams-sdk';  | 
69 | 108 | 
 
  | 
70 |  | -## Environment Variables  | 
 | 109 | +const frontendClient = new FrontendAuthClient({  | 
 | 110 | +  clientId: 'your-client-id',  | 
 | 111 | +  redirectUri: 'https://yourapp.com/callback',  | 
 | 112 | +  baseUrl: 'https://your-site.stackenterprise.co'  | 
 | 113 | +}, '/api'); // Your backend API base URL  | 
71 | 114 | 
 
  | 
72 |  | -For security, store your access tokens in environment variables:  | 
 | 115 | +// Start authentication flow  | 
 | 116 | +const authUrl = await frontendClient.startAuth();  | 
 | 117 | +window.location.href = authUrl;  | 
73 | 118 | 
 
  | 
74 |  | -```typescript title="config.ts"  | 
75 |  | -export const config = {  | 
76 |  | -  baseUrl: process.env.STACKOVERFLOW_BASE_URL,  | 
77 |  | -  accessToken: process.env.STACKOVERFLOW_ACCESS_TOKEN  | 
78 |  | -};  | 
 | 119 | +// Handle OAuth callback  | 
 | 120 | +await frontendClient.handleCallback();  | 
 | 121 | + | 
 | 122 | +// Check authentication status  | 
 | 123 | +const isAuthenticated = await frontendClient.getAuthStatus();  | 
 | 124 | + | 
 | 125 | +// Manual token submission (for PATs)  | 
 | 126 | +const success = await frontendClient.submitAccessToken(userToken);  | 
79 | 127 | ```  | 
80 | 128 | 
 
  | 
81 |  | -```typescript title="app.ts"  | 
82 |  | -import StackOverflowSDK from 'so-teams-sdk;  | 
83 |  | -import { config } from './config';  | 
 | 129 | +## Authentication Configuration  | 
84 | 130 | 
 
  | 
85 |  | -const sdk = new StackOverflowSDK(config);  | 
 | 131 | +### AuthConfig Interface  | 
 | 132 | + | 
 | 133 | +```typescript  | 
 | 134 | +interface AuthConfig {  | 
 | 135 | +  /** OAuth client ID from Stack Overflow Enterprise */  | 
 | 136 | +  clientId: string;  | 
 | 137 | +  /** Redirect URI registered with your application */  | 
 | 138 | +  redirectUri: string;    | 
 | 139 | +  /** Stack Overflow Enterprise instance URL */  | 
 | 140 | +  baseUrl: string;  | 
 | 141 | +  /** OAuth scopes (optional) */  | 
 | 142 | +  scope?: string;  | 
 | 143 | +}  | 
86 | 144 | ```  | 
87 | 145 | 
 
  | 
88 |  | -## Token Management  | 
 | 146 | +### Available Methods  | 
 | 147 | + | 
 | 148 | +#### BackendAuthClient Methods  | 
 | 149 | + | 
 | 150 | +| Method | Description | Returns |  | 
 | 151 | +|--------|-------------|---------|  | 
 | 152 | +| `generatePKCETokens()` | Generate PKCE tokens for secure OAuth | `Promise<PKCETokens>` |  | 
 | 153 | +| `getAuthUrl()` | Generate authorization URL with PKCE | `Promise<{url, codeVerifier, state}>` |  | 
 | 154 | +| `exchangeCodeForToken()` | Exchange auth code for access token | `Promise<TokenResponse>` |  | 
 | 155 | +| `validateState()` | Validate state parameter for CSRF protection | `boolean` |  | 
 | 156 | + | 
 | 157 | +#### FrontendAuthClient Methods  | 
 | 158 | + | 
 | 159 | +| Method | Description | Returns |  | 
 | 160 | +|--------|-------------|---------|  | 
 | 161 | +| `startAuth()` | Start OAuth flow via backend API | `Promise<string>` |  | 
 | 162 | +| `completeAuth()` | Complete OAuth with callback params | `Promise<void>` |  | 
 | 163 | +| `handleCallback()` | Handle OAuth callback in current page | `Promise<void>` |  | 
 | 164 | +| `getAuthStatus()` | Check if user is authenticated | `Promise<boolean>` |  | 
 | 165 | +| `submitAccessToken()` | Submit manual access token | `Promise<boolean>` |  | 
 | 166 | +| `logout()` | Clear authentication state | `Promise<boolean>` |  | 
 | 167 | + | 
 | 168 | +## Token Scopes  | 
 | 169 | + | 
 | 170 | +Different API operations require different scopes:  | 
89 | 171 | 
 
  | 
90 |  | -### Token Expiration  | 
 | 172 | +| Scope | Description |  | 
 | 173 | +|-------|-------------|  | 
 | 174 | +| read_inbox | Access user's inbox |  | 
 | 175 | +| write_access | Perform write operations |  | 
 | 176 | +| private_info | Access private user data |  | 
 | 177 | +| no_expiry | Token never expires (use with caution) |  | 
 | 178 | + | 
 | 179 | +## Security Best Practices  | 
91 | 180 | 
 
  | 
92 |  | -Unless you use the `no_expiry` scope, access tokens expire after 24 hours. Monitor token expiration and implement refresh logic as needed.  | 
 | 181 | +<CardGrid>  | 
 | 182 | +  <Card title="PKCE Implementation" icon="shield">  | 
 | 183 | +    The SDK automatically implements PKCE (Proof Key for Code Exchange) to prevent authorization code interception attacks.  | 
 | 184 | +  </Card>  | 
 | 185 | +  <Card title="State Validation" icon="lock">  | 
 | 186 | +    Always validate the state parameter in OAuth callbacks to prevent CSRF attacks using the built-in validation methods.  | 
 | 187 | +  </Card>  | 
 | 188 | +  <Card title="Secure Token Storage" icon="certificate">  | 
 | 189 | +    Follow secure token storage best practices and avoid client-side storage for sensitive authentication data.  | 
 | 190 | +  </Card>  | 
 | 191 | +  <Card title="Environment Variables" icon="key">  | 
 | 192 | +    Keep sensitive configuration like client IDs and secrets in environment variables, not in your source code.  | 
 | 193 | +  </Card>  | 
 | 194 | +</CardGrid>  | 
93 | 195 | 
 
  | 
94 |  | -### Error Handling  | 
 | 196 | +## Error Handling  | 
95 | 197 | 
 
  | 
96 | 198 | Handle authentication errors gracefully:  | 
97 | 199 | 
 
  | 
98 | 200 | ```typescript title="auth-error-handling.ts"  | 
99 |  | -async function makeAuthenticatedRequest() {  | 
 | 201 | +async function authenticateUser() {  | 
100 | 202 |   try {  | 
101 |  | -    const questions = await sdk.questions.getQuestions();  | 
102 |  | -    return questions;  | 
 | 203 | +    const authUrl = await authClient.getAuthUrl();  | 
 | 204 | +    // Handle success  | 
103 | 205 |   } catch (error) {  | 
104 |  | -    if (error.status === 401) {  | 
105 |  | -      console.error('Authentication failed - token may be expired or invalid');  | 
106 |  | -      // Implement token refresh or re-authentication logic  | 
107 |  | -    } else if (error.status === 403) {  | 
108 |  | -      console.error('Insufficient permissions - check token scopes');  | 
 | 206 | +    if (error.message.includes('clientId')) {  | 
 | 207 | +      console.error('Missing OAuth configuration');  | 
 | 208 | +    } else {  | 
 | 209 | +      console.error('Authentication setup failed:', error);  | 
109 | 210 |     }  | 
110 |  | -    throw error;  | 
111 | 211 |   }  | 
112 | 212 | }  | 
 | 213 | + | 
 | 214 | +// In callback handler  | 
 | 215 | +try {  | 
 | 216 | +  const tokens = await authClient.exchangeCodeForToken(code, codeVerifier);  | 
 | 217 | +} catch (error) {  | 
 | 218 | +  if (error.message.includes('Failed to exchange')) {  | 
 | 219 | +    console.error('Token exchange failed - check OAuth configuration');  | 
 | 220 | +  }  | 
 | 221 | +  throw error;  | 
 | 222 | +}  | 
113 | 223 | ```  | 
114 | 224 | 
 
  | 
115 |  | -## Security Best Practices  | 
 | 225 | +## Alternative: Personal Access Tokens  | 
116 | 226 | 
 
  | 
117 |  | -<CardGrid>  | 
118 |  | -  <Card title="Secure Storage" icon="lock">  | 
119 |  | -    Never hardcode access tokens in your source code. Use environment variables or secure configuration management.  | 
120 |  | -  </Card>  | 
121 |  | -  <Card title="Token Rotation" icon="refresh">  | 
122 |  | -    Regularly rotate your access tokens and implement proper token lifecycle management.  | 
123 |  | -  </Card>  | 
124 |  | -  <Card title="Scope Limitation" icon="shield">  | 
125 |  | -    Request only the minimum scopes required for your application functionality.  | 
126 |  | -  </Card>  | 
127 |  | -  <Card title="HTTPS Only" icon="certificate">  | 
128 |  | -    Always use HTTPS when transmitting access tokens to prevent interception.  | 
129 |  | -  </Card>  | 
130 |  | -</CardGrid>  | 
 | 227 | +### Enterprise Instances  | 
 | 228 | +For simpler Enterprise implementations, you can generate Tokens manually and use them as seen below:  | 
 | 229 | + | 
 | 230 | +```typescript  | 
 | 231 | +const sdk = StackOverflowSDK.fromToken(  | 
 | 232 | +  'your-enterprise-pat',  | 
 | 233 | +  'https://your-site.stackenterprise.co'  | 
 | 234 | +);  | 
 | 235 | + | 
 | 236 | +const questions = await sdk.questions.getAll();  | 
 | 237 | +```  | 
 | 238 | + | 
 | 239 | +You'll need to follow [this guide](https://stackoverflowteams.help/en/articles/9718149-secure-api-token-generation-with-oauth-and-pkce) to understand how OAuth works on Enterprise.  | 
 | 240 | + | 
 | 241 | +### Basic/Business Instances (Required)  | 
 | 242 | +For Basic and Business tiers, PATs are the only authentication method available:  | 
 | 243 | + | 
 | 244 | +**[Personal Access Tokens (PATs) for API Authentication →](https://stackoverflowteams.help/en/articles/10908790-personal-access-tokens-pats-for-api-authentication)**  | 
 | 245 | + | 
 | 246 | +```typescript  | 
 | 247 | +const sdk = StackOverflowSDK.fromToken(userProvidedPAT, 'https://api.stackoverflowteams.com/v3');  | 
 | 248 | +const teamContext = sdk.forTeam('team-123');  | 
 | 249 | +```  | 
131 | 250 | 
 
  | 
132 | 251 | ## Next Steps  | 
133 | 252 | 
 
  | 
134 |  | -Once you have your access token configured:  | 
 | 253 | +Once you have authentication configured with the helpers:  | 
135 | 254 | 
 
  | 
136 |  | -- [Quickstart Guide](/quickstart) - Get started with the SDK  | 
137 |  | -- [Questions API](/questions/getall/) - Learn about fetching questions  | 
138 |  | -- [Rate Limits](/guides/rate-limiting) - Understand how rate limits work on SO Teams  | 
 | 255 | +- [Quickstart Guide](/guides/quickstart) - Get started with the SDK  | 
 | 256 | +- [Questions API](/questions/getall/) - Learn about fetching questions    | 
 | 257 | +- [Rate Limits](/guides/rate-limiting) - Understand API rate limits  | 
139 | 258 | 
 
  | 
140 | 259 | :::note[Rate Limits]  | 
141 |  | -Authentication doesn't bypass API rate limits. Authenticated requests typically have higher rate limits than anonymous requests, but limits still apply.  | 
 | 260 | +Authentication doesn't bypass API rate limits.  | 
142 | 261 | :::  | 
143 | 262 | 
 
  | 
144 | 263 | :::tip[Development vs Production]  | 
145 |  | -Use different access tokens for development and production environments. Consider using shorter-lived tokens in production for enhanced security.  | 
 | 264 | +Use different OAuth applications and tokens for development and production environments. The authentication helpers support this through environment-specific configuration.  | 
146 | 265 | :::  | 
0 commit comments