Authentication & Setup
Written By Stanislas
Last updated 16 days ago
Authenticate your users with the Swiftask Public Bot API using a simple REST endpoint, then configure your GraphQL client for subsequent API calls.
Overview
The Swiftask authentication process is a two-step flow: first, you exchange your client token and a user identifier (client UUID) for an access token via REST; second, you configure your GraphQL client with that token to make authenticated API requests.
This guide covers how to implement authentication, store credentials securely, and set up your GraphQL and WebSocket clients for real-time features.
Prerequisites
Before you authenticate, ensure you have:
Client Token β A unique token for your agent (obtained from your Swiftask workspace Developer section)
Client UUID β A unique identifier for each user or session (generated client-side)
GraphQL client library β Apollo Client or a similar GraphQL client (already installed)
Obtaining your client token
Log in to your Swiftask workspace
Navigate to your agent's Developer section
Find the API Access area and copy your
clientTokenKeep this token secure; it identifies your agent to the API
Getting started
Here's the minimal setup to authenticate and create a GraphQL client:
Step 1: Generate a client UUID
The client UUID uniquely identifies a user or session on the client side. Generate it once and store it for persistence.
// Method 1: Using the browser Crypto API (recommended)
const clientUuid = crypto.randomUUID();
localStorage.setItem('swiftask_client_uuid', clientUuid);
// Method 2: Using the uuid library (if installed)
import { v4 as uuidv4 } from 'uuid';
const clientUuid = uuidv4();
localStorage.setItem('swiftask_client_uuid', clientUuid);
// Retrieve on subsequent visits
const storedUuid = localStorage.getItem('swiftask_client_uuid') || crypto.randomUUID();
Step 2: Call the REST authentication endpoint
Exchange your client token and UUID for an access token.
const clientToken = 'your_agent_client_token';
const clientUuid = localStorage.getItem('swiftask_client_uuid') || crypto.randomUUID();
const response = await fetch(`https://graphql.swiftask.ai/public/widget-bot/${clientToken}`, {
method: 'GET',
headers: {
'x-client-uuid': clientUuid,
'Content-Type': 'application/json',
},
});
const result = await response.json();
if (result.success) {
const { accessToken, botSlug, todoId, workspaceId, starterSessionId } = result.data;
console.log('Authentication successful');
} else {
console.error('Authentication failed:', result.error);
}
Step 3: Configure your GraphQL client
Use the accessToken and workspaceId from the authentication response to set up Apollo Client.
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
const httpLink = createHttpLink({
uri: 'https://graphql.swiftask.ai/graphql',
});
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
authorization: `Bearer ${accessToken}`,
'x-workspace-id': workspaceId, // Required for request routing
'x-client': 'widget', // Identifies this as a public widget client
},
};
});
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
});
Understanding the authentication response
The REST endpoint returns a configuration object with everything you need to proceed:
Store these values; you'll use them for subsequent API calls.
Setting up WebSocket for real-time features
If you plan to use subscriptions (real-time message streaming, tool call events, etc.), configure a WebSocket connection alongside your HTTP GraphQL client.
import { WebSocketLink } from '@apollo/client/link/ws';
import { split } from '@apollo/client';
import { getMainDefinition } from '@apollo/client/utilities';
const wsLink = new WebSocketLink({
uri: 'wss://graphql.swiftask.ai/graphql',
options: {
reconnect: true,
connectionParams: {
authorization: `Bearer ${accessToken}`,
workspaceId: workspaceId, // Required for WebSocket routing
},
},
});
// Split: queries/mutations use HTTP, subscriptions use WebSocket
const splitLink = split(
({ query }) => {
const definition = getMainDefinition(query);
return definition.kind === 'OperationDefinition' && definition.operation === 'subscription';
},
wsLink,
authLink.concat(httpLink)
);
const client = new ApolloClient({
link: splitLink,
cache: new InMemoryCache(),
});
Complete authentication class
Here's a reusable class that handles the full authentication flow and client setup:
class SwiftaskAuthClient {
constructor(clientToken, apiUrl = 'https://graphql.swiftask.ai') {
this.clientToken = clientToken;
this.apiUrl = apiUrl;
this.clientUuid = this.getOrCreateClientUuid();
this.config = null;
this.client = null;
}
getOrCreateClientUuid() {
let uuid = localStorage.getItem('swiftask_client_uuid');
if (!uuid) {
uuid = crypto.randomUUID();
localStorage.setItem('swiftask_client_uuid', uuid);
}
return uuid;
}
async authenticate() {
const response = await fetch(
`${this.apiUrl}/public/widget-bot/${this.clientToken}`,
{
method: 'GET',
headers: {
'x-client-uuid': this.clientUuid,
'Content-Type': 'application/json',
},
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error?.message || 'Authentication failed');
}
const result = await response.json();
if (!result.success) {
throw new Error('Authentication failed');
}
this.config = result.data;
return this.config;
}
setupGraphQLClient() {
if (!this.config) {
throw new Error('Not authenticated. Call authenticate() first.');
}
const httpLink = createHttpLink({
uri: `${this.apiUrl}/graphql`,
});
const authLink = setContext((_, { headers }) => ({
headers: {
...headers,
authorization: `Bearer ${this.config.accessToken}`,
'x-workspace-id': this.config.workspaceId,
'x-client': 'widget',
},
}));
const wsLink = new WebSocketLink({
uri: `wss://graphql.swiftask.ai/graphql`,
options: {
reconnect: true,
connectionParams: {
authorization: `Bearer ${this.config.accessToken}`,
workspaceId: this.config.workspaceId,
},
},
});
const splitLink = split(
({ query }) => {
const definition = getMainDefinition(query);
return definition.kind === 'OperationDefinition' && definition.operation === 'subscription';
},
wsLink,
authLink.concat(httpLink)
);
this.client = new ApolloClient({
link: splitLink,
cache: new InMemoryCache(),
});
return this.client;
}
getClient() {
if (!this.client) {
throw new Error('GraphQL client not initialized. Call setupGraphQLClient() first.');
}
return this.client;
}
getConfig() {
return this.config;
}
}
// Usage
const authClient = new SwiftaskAuthClient('your_client_token');
await authClient.authenticate();
const client = authClient.setupGraphQLClient();
Handling authentication errors
The REST endpoint may return errors. Handle them gracefully:
const authenticateWithErrorHandling = async (clientToken, clientUuid) => {
try {
const response = await fetch(
`https://graphql.swiftask.ai/public/widget-bot/${clientToken}`,
{
headers: { 'x-client-uuid': clientUuid },
}
);
if (!response.ok) {
const error = await response.json();
switch (response.status) {
case 400:
throw new Error('Invalid request: Check your parameters');
case 401:
throw new Error('Authentication failed: Invalid client token');
case 403:
throw new Error('Access denied: Agent may not be public');
case 404:
throw new Error('Agent not found');
case 500:
throw new Error('Server error: Try again later');
default:
throw new Error(`Unknown error: ${response.status}`);
}
}
return await response.json();
} catch (error) {
if (error instanceof TypeError) {
throw new Error('Network error: Check your connection');
}
throw error;
}
};
Best practices
Store the client UUID persistently β Always save it to localStorage or equivalent storage so the same user is recognized across sessions.
Keep your client token secure β Never expose it in client-side code repositories. Use environment variables or secure backend proxies in production.
Treat the access token as sensitive β Store it securely and never log it to the console in production.
Implement token refresh logic β Tokens may expire. Check the token's expiration time and refresh when needed.
Use HTTPS/WSS in production β Always use secure connections for authentication and real-time features.
Handle network errors gracefully β Implement retry logic with exponential backoff for transient failures.
Validate the response structure β Always check that the authentication response contains expected fields before using them.