OAuth 2.0
Authenticate on behalf of users with OAuth 2.0.
OAuth 2.0
OAuth 2.0 enables your app to access Coline on behalf of users. It's the right choice when:
- Building apps for the Coline marketplace
- Integrating with external services
- Acting on behalf of multiple users
- Needing limited, user-granted permissions
How It Works
- User Authorization — User grants your app permission
- Authorization Code — Coline redirects to your app with a code
- Token Exchange — Your app exchanges code for access token
- API Access — Use token to make API requests
Registering Your App
Before using OAuth, register your application:
- Go to Coline Developers
- Click New Application
- Enter app details:
- Name
- Description
- Redirect URIs (must be HTTPS)
- Required scopes
- Save your Client ID and Client Secret
Important: Never expose the Client Secret in client-side code.
Authorization Flow
Step 1: Redirect User to Authorization URL
import { buildLoginWithColineAuthorizeUrl, createOauthState, createPkceCodeChallenge } from '@colineapp/sdk'
// Generate state and PKCE for security
const state = createOauthState()
const { codeVerifier, codeChallenge } = createPkceCodeChallenge()
// Store for later verification
session.oauthState = state
session.codeVerifier = codeVerifier
const authUrl = buildLoginWithColineAuthorizeUrl({
clientId: CLIENT_ID,
redirectUri: 'https://your-app.com/auth/callback',
scope: 'files:read messages:read',
state,
codeChallenge,
codeChallengeMethod: 'S256'
})
// Redirect user
res.redirect(authUrl)Parameters:
| Parameter | Required | Description |
|---|---|---|
client_id | Yes | Your app's Client ID |
redirect_uri | Yes | Must match registered URI |
response_type | Yes | Always code |
scope | Yes | Space-separated scopes |
state | Recommended | Random string for CSRF protection |
code_challenge | Recommended | PKCE code challenge |
code_challenge_method | Recommended | S256 or plain |
Step 2: Handle the Callback
After authorization, Coline redirects to your redirect_uri:
https://your-app.com/auth/callback?code=abc123&state=xyz789Verify the state parameter matches what you sent:
if (req.query.state !== session.oauthState) {
throw new Error('Invalid state parameter')
}Step 3: Exchange Code for Token
const response = await fetch('https://api.coline.app/v1/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
grant_type: 'authorization_code',
code: req.query.code,
redirect_uri: 'https://your-app.com/auth/callback',
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
code_verifier: session.codeVerifier // Required if using PKCE
})
})
const { access_token, refresh_token, expires_in, scope } = await response.json()Response:
{
"access_token": "col_at_...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "col_rt_...",
"scope": "files:read messages:read"
}Step 4: Use the Access Token
OAuth tokens work as API keys:
import { ColineApiClient } from '@colineapp/sdk'
const client = new ColineApiClient({
baseUrl: 'https://api.coline.app',
apiKey: access_token // OAuth tokens work as API keys
})
const ws = client.workspace('ws_abc123')
const files = await ws.listDriveFiles('drive_xyz')Refresh Tokens
Access tokens expire after 1 hour. Use refresh tokens to get new access tokens without re-authorizing the user:
const response = await fetch('https://api.coline.app/v1/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
grant_type: 'refresh_token',
refresh_token: storedRefreshToken,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET
})
})
const { access_token, refresh_token } = await response.json()
// Store new tokens (refresh_token may be new)Important: Refresh tokens are single-use. The response includes a new refresh token — store it and discard the old one.
Scopes
Scopes define what your app can access. Request only the scopes you need.
Common Scopes:
files:read— Read files and foldersfiles:write— Create and modify filesmessages:read— Read channel messagesmessages:write— Send messagestasks:read— Read tasks and taskboardstasks:write— Create and update taskscalendar:read— Read calendar eventscalendar:write— Create and modify eventsworkspace:read— Read workspace info and members
See Scopes for complete list.
Error Handling
Authorization Errors:
https://your-app.com/auth/callback?error=access_denied&error_description=user+denied+accessCommon Errors:
| Error | Description |
|---|---|
invalid_request | Missing or invalid parameters |
invalid_client | Client ID or secret is wrong |
invalid_grant | Authorization code is expired or invalid |
unauthorized_client | App is not authorized for this grant type |
access_denied | User denied authorization |
unsupported_response_type | Response type not supported |
invalid_scope | Requested scope is invalid |
Revoking Access
Users can revoke your app's access from their Coline settings. Handle 401 responses gracefully and prompt for re-authorization.
Testing OAuth
Use the OAuth Playground to test your implementation without writing code.
Next Steps
- Scopes — Available permission scopes
- Security Best Practices — Keep your OAuth implementation secure
- Building Integrations — Create full integrations