Authorization flow
Four steps get you from “Connect with LifeBots” to an access token. Pick your app type — the code changes to match.
1. Send the user to LifeBots
Redirect the user's browser to the authorize URL with your client_id, redirect URI, the scopes you want, and a random state.
// Remember state so the callback can prove the redirect is yours
const state = crypto.randomUUID()
sessionStorage.setItem('oauth_state', state)
const authUrl = new URL('https://lifebots.cloud/oauth/authorize')
authUrl.searchParams.set('client_id', 'your_client_id')
authUrl.searchParams.set('redirect_uri', 'https://yourapp.com/oauth/callback')
authUrl.searchParams.set('scope', 'read:profile bots:chat bots:groups') // space-separated
authUrl.searchParams.set('state', state)
window.location.href = authUrl.toString()The user signs in, sees your app's name and the scopes, and approves. If they already approved the same scopes before, they're sent straight back. All authorize parameters →
2. Handle the redirect back
LifeBots redirects to your redirect_uri with ?code=…&state=…, or with ?error=access_denied if the user declined. Reject any redirect whose state isn't the one you stored.
// On https://yourapp.com/oauth/callback
const params = new URLSearchParams(window.location.search)
if (params.get('state') !== sessionStorage.getItem('oauth_state')) {
throw new Error('State mismatch - ignore this redirect')
}
if (params.get('error')) {
// access_denied: the user said no
throw new Error(params.get('error_description') || params.get('error'))
}
const code = params.get('code') // single-use and short-lived: exchange it now3. Exchange the code for tokens
Send the code with your client_secret, from your server.
// On your server - the client_secret must never reach a browser
const res = await fetch('https://api.lifebots.cloud/api/v1/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: 'your_client_id',
client_secret: process.env.LIFEBOTS_CLIENT_SECRET,
code,
redirect_uri: 'https://yourapp.com/oauth/callback' // same as step 1
})
})
const tokens = await res.json()
if (tokens.error) throw new Error(tokens.error_description){
"access_token": "lb_at_…",
"token_type": "Bearer",
"scope": "read:profile bots:chat bots:groups",
"refresh_token": "lb_rt_…",
"expires_in": 3600
}refresh_tokenis only included if your app has token refresh turned on.expires_in(seconds) is left out when your app's tokens never expire.
4. Refresh when the token expires
When a call fails with INVALID_TOKEN, trade the refresh token for a new pair. Tokens rotate: after a refresh the old access and refresh tokens are dead, so store the new ones before your next call.
const res = await fetch('https://api.lifebots.cloud/api/v1/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'refresh_token',
client_id: 'your_client_id',
client_secret: process.env.LIFEBOTS_CLIENT_SECRET,
refresh_token: tokens.refresh_token
})
})
const newTokens = await res.json()
// The old access AND refresh tokens stop working now - save the new pair.