Bouton "Se connecter avec Octal Group"

Intégrez le bouton officiel dans vos interfaces pour offrir une connexion rapide et sécurisée.

Aperçu des variantes

Variante claire (recommandée)

Variante sombre

Règles d'utilisation

À faire

  • Utiliser exactement le texte "Se connecter avec Octal Group"
  • Maintenir une taille minimale de 40px de hauteur
  • Conserver les proportions et l'espacement du logo
  • Placer le bouton sur un fond contrasté

À éviter

  • Modifier les couleurs du logo ou du texte
  • Utiliser le logo Octal Group seul sans le texte "Se connecter"
  • Déformer, tourner ou redimensionner le logo
  • Ajouter des effets (ombre, gradient) sur le logo

Code HTML — Variante claire

Copiez ce code dans votre formulaire de connexion :

<a href="https://account.groupeoctal.com/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_CALLBACK&response_type=code&scope=openid+profile+email&state=RANDOM_STATE"
   class="octal-signin-btn">
  <img src="https://account.groupeoctal.com/images/logo.svg" alt="Octal Group">
  Se connecter avec Octal Group
</a>

CSS officiel

Styles à inclure dans votre feuille de style :

/* Octal Group Sign-In Button */
.octal-signin-btn {
  display: inline-flex;
  align-items: center;
  padding: 10px 20px;
  background: #ffffff;
  border: 2px solid #e5e7eb;
  border-radius: 10px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  color: #1f2937;
  text-decoration: none;
  cursor: pointer;
  transition: all 0.2s ease;
  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
  gap: 10px;
}

.octal-signin-btn img {
  width: 22px;
  height: 22px;
}

.octal-signin-btn:hover {
  border-color: #818cf8;
  box-shadow: 0 4px 12px rgba(99,102,241,0.15);
  transform: translateY(-1px);
}

/* Variante sombre */
.octal-signin-btn--dark {
  background: #4f46e5;
  border-color: #4f46e5;
  color: #ffffff;
}

.octal-signin-btn--dark:hover {
  background: #4338ca;
  border-color: #4338ca;
}

Implémentation JavaScript (avec PKCE)

Implémentation sécurisée avec PKCE pour les applications SPA ou mobile :

class OctalAuth {
  constructor(config) {
    this.clientId     = config.clientId;
    this.redirectUri  = config.redirectUri;
    this.baseUrl      = 'https://account.groupeoctal.com';
    this.scopes       = config.scopes || 'openid profile email';
  }

  async login() {
    const state        = this._randomString(32);
    const codeVerifier = this._randomString(64);
    const codeChallenge = await this._sha256(codeVerifier);

    sessionStorage.setItem('octal_state', state);
    sessionStorage.setItem('octal_code_verifier', codeVerifier);

    const params = new URLSearchParams({
      client_id:             this.clientId,
      redirect_uri:          this.redirectUri,
      response_type:         'code',
      scope:                 this.scopes,
      state,
      code_challenge:        codeChallenge,
      code_challenge_method: 'S256',
    });

    window.location.href = `${this.baseUrl}/oauth/authorize?${params}`;
  }

  async handleCallback(callbackUrl) {
    const url    = new URL(callbackUrl);
    const code   = url.searchParams.get('code');
    const state  = url.searchParams.get('state');
    const stored = sessionStorage.getItem('octal_state');

    if (state !== stored) throw new Error('State mismatch — possible CSRF');

    const codeVerifier = sessionStorage.getItem('octal_code_verifier');
    sessionStorage.removeItem('octal_state');
    sessionStorage.removeItem('octal_code_verifier');

    const res = await fetch(`${this.baseUrl}/oauth/token`, {
      method:  'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body:    new URLSearchParams({
        grant_type:    'authorization_code',
        code,
        redirect_uri:  this.redirectUri,
        client_id:     this.clientId,
        code_verifier: codeVerifier,
      }),
    });

    return res.json();  // { access_token, refresh_token, expires_in }
  }

  async getUserInfo(accessToken) {
    const res = await fetch(`${this.baseUrl}/oauth/userinfo`, {
      headers: { Authorization: `Bearer ${accessToken}` },
    });
    return res.json();
  }

  _randomString(length) {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
    return Array.from(crypto.getRandomValues(new Uint8Array(length)))
      .map(b => chars[b % chars.length]).join('');
  }

  async _sha256(plain) {
    const encoder = new TextEncoder();
    const data    = encoder.encode(plain);
    const digest  = await crypto.subtle.digest('SHA-256', data);
    return btoa(String.fromCharCode(...new Uint8Array(digest)))
      .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
  }
}

// Utilisation
const auth = new OctalAuth({
  clientId:    'YOUR_CLIENT_ID',
  redirectUri: 'https://votre-app.com/callback',
});

document.getElementById('octal-signin').addEventListener('click', () => auth.login());

Composant React

import React from 'react';

export default function OctalSignInButton({ clientId, redirectUri, label = 'Se connecter avec Octal Group', dark = false }) {
  const handleLogin = async () => {
    const state = crypto.randomUUID();
    sessionStorage.setItem('octal_state', state);

    const url = `https://account.groupeoctal.com/oauth/authorize?` + new URLSearchParams({
      client_id: clientId, redirect_uri: redirectUri,
      response_type: 'code', scope: 'openid profile email', state,
    });
    window.location.href = url;
  };

  return (
    <button
      onClick={handleLogin}
      className={`octal-signin-btn ${dark ? 'octal-signin-btn--dark' : ''}`}
    >
      <img src="https://account.groupeoctal.com/images/logo.svg" alt="" width="22" height="22" />
      {label}
    </button>
  );
}

// Utilisation :
// <OctalSignInButton clientId="YOUR_ID" redirectUri="https://votre-app.com/callback" />
// <OctalSignInButton dark label="Continuer avec Octal Group" ... />

Gestion du callback

Une fois l'utilisateur redirigé vers votre redirect_uri, vous recevez :

https://votre-app.com/callback?code=AUTH_CODE&state=STATE_VALUE
1

Vérifiez que state correspond à la valeur que vous aviez envoyée (anti-CSRF).

2

Échangez code contre un access token via POST /oauth/token (côté serveur).

3

Récupérez le profil utilisateur via GET /oauth/userinfo.

4

Créez ou mettez à jour l'utilisateur dans votre base de données en utilisant le champ sub comme identifiant unique.