Coline Docs
Authentication

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

  1. User Authorization — User grants your app permission
  2. Authorization Code — Coline redirects to your app with a code
  3. Token Exchange — Your app exchanges code for access token
  4. API Access — Use token to make API requests

Registering Your App

Before using OAuth, register your application:

  1. Go to Coline Developers
  2. Click New Application
  3. Enter app details:
    • Name
    • Description
    • Redirect URIs (must be HTTPS)
    • Required scopes
  4. 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:

ParameterRequiredDescription
client_idYesYour app's Client ID
redirect_uriYesMust match registered URI
response_typeYesAlways code
scopeYesSpace-separated scopes
stateRecommendedRandom string for CSRF protection
code_challengeRecommendedPKCE code challenge
code_challenge_methodRecommendedS256 or plain

Step 2: Handle the Callback

After authorization, Coline redirects to your redirect_uri:

https://your-app.com/auth/callback?code=abc123&state=xyz789

Verify 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 folders
  • files:write — Create and modify files
  • messages:read — Read channel messages
  • messages:write — Send messages
  • tasks:read — Read tasks and taskboards
  • tasks:write — Create and update tasks
  • calendar:read — Read calendar events
  • calendar:write — Create and modify events
  • workspace: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+access

Common Errors:

ErrorDescription
invalid_requestMissing or invalid parameters
invalid_clientClient ID or secret is wrong
invalid_grantAuthorization code is expired or invalid
unauthorized_clientApp is not authorized for this grant type
access_deniedUser denied authorization
unsupported_response_typeResponse type not supported
invalid_scopeRequested 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

On this page