Authentification et configuration

Écrit par Stanislas

Dernière mise à jour Il y a 7 mois


Authentifiez vos utilisateurs avec l'API Swiftask Public Bot à l'aide d'un simple point d'extrémité REST, puis configurez votre client GraphQL pour les appels d'API ultérieurs.

Présentation

Le processus d'authentification Swiftask se déroule en deux étapes : tout d'abord, vous échangez votre jeton client et un identifiant utilisateur (UUID client) contre un jeton d'accès via REST ; ensuite, vous configurez votre client GraphQL avec ce jeton pour effectuer des requêtes API authentifiées.

Ce guide explique comment implémenter l'authentification, stocker les informations d'identification en toute sécurité et configurer vos clients GraphQL et WebSocket pour les fonctionnalités en temps réel.


Prérequis

Avant de vous authentifier, assurez-vous de disposer des éléments suivants :

  1. Jeton client — Un jeton unique pour votre agent (obtenu dans la section Développeur de votre espace de travail Swiftask)

  2. UUID client — Un identifiant unique pour chaque utilisateur ou session (généré côté client)

  3. Bibliothèque client GraphQL — Apollo Client ou un client GraphQL similaire (déjà installé)

Obtenir votre jeton client

  1. Connectez-vous à votre espace de travail Swiftask

  2. Accédez à la section Développeur de votre agent

  3. Recherchez la zone Accès API et copiez votre jeton d'accès (clientToken)

  4. Conservez ce jeton en lieu sûr ; il identifie votre agent auprès de l'API


Pour commencer

Voici la configuration minimale pour authentifier et créer un client GraphQL :

Étape 1 : Générer un UUID client

L'UUID client identifie de manière unique un utilisateur ou une session côté client. Générez-le une seule fois et conservez-le pour plus de persistance.

// 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();

Étape 2 : Appelez le point de terminaison d'authentification REST

Échangez votre jeton client et votre UUID contre un jeton d'accès.

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);
}

Étape 3 : Configurez votre client GraphQL

Utilisez l'accessTokene et l'workspaceIde de la réponse d'authentification pour configurer 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(),
});

Comprendre la réponse d'authentification

Le point de terminaison REST renvoie un objet de configuration contenant tout ce dont vous avez besoin pour continuer :

Champ

Type

Objectif

accessToken

chaîne

Jeton JWT pour l'authentification des requêtes GraphQL

botSlug

chaîne

Identifiant unique pour votre agent

todoId

nom

ID du conteneur pour les sessions de chat de cet utilisateur

workspaceId

num

ID de l'espace de travail de votre agent (requis pour les en-têtes GraphQL)

starterSessionId

numéro

Une session de chat par défaut, prête à être utilisée immédiatement

clientUuid

chaîne

Écho de l'UUID client que vous avez envoyé

widgetAppearance

objet

Configuration de l'apparence de votre widget de chat

Enregistrez ces valeurs ; vous les utiliserez pour les appels API suivants.

Configuration de WebSocket pour les fonctionnalités en temps réel

Si vous prévoyez d'utiliser des abonnements (diffusion de messages en temps réel, événements d'appel d'outils, etc.), configurez une connexion WebSocket en plus de votre client HTTP GraphQL.

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(),
});

Classe d'authentification complète

Voici une classe réutilisable qui gère l'ensemble du flux d'authentification et la configuration du client :

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();

Gestion des erreurs d'authentification

Le point de terminaison REST peut renvoyer des erreurs. Gérez-les avec élégance :

Statut HTTP

Code d'erreur

Signification

Action

400

Demande incorrecte

Paramètres manquants ou non valides

Vérifiez vos en-têtes clientToken et x-client-uuid

401

Non autorisé

Jeton invalide ou expiré

Vérifiez que votre clientToken est correct.

403

Interdit

L'agent n'est pas public

Activez l'accès public dans les paramètres de votre agent

404

Introuvable

L'agent n'existe pas

Vérifiez que l'agent existe dans votre espace de travail

500

Erreur interne du serveur

Problème côté serveur

Réessayez après un court délai

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;
  }
};

Bonnes pratiques

  1. Stockez l'UUID du client de manière permanente — Enregistrez-le toujours dans localStorage ou un stockage équivalent afin que le même utilisateur soit reconnu d'une session à l'autre.

  2. Protégez votre jeton client — Ne l'exposez jamais dans les référentiels de code côté client. Utilisez des variables d'environnement ou des proxys backend sécurisés en production.

  3. Traitez le jeton d'accès comme une information sensible — Stockez-le de manière sécurisée et ne l'enregistrez jamais dans la console en production.

  4. Implémentez une logique de rafraîchissement des jetons — Les jetons peuvent expirer. Vérifiez la date d'expiration du jeton et rafraîchissez-le si nécessaire.

  5. Utilisez HTTPS/WSS en production — Utilisez toujours des connexions sécurisées pour l'authentification et les fonctionnalités en temps réel.

  6. Gérez les erreurs réseau avec élégance : implémentez une logique de réessai avec un délai exponentiel pour les échecs transitoires.

  7. Validez la structure de la réponse : vérifiez toujours que la réponse d'authentification contient les champs attendus avant de les utiliser.