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.