UNPKG

@passkey-fas/webauthn-sdk

Version:

Official JavaScript SDK for FaS (FIDO2 as Service) Platform - Easy passwordless authentication integration

514 lines (400 loc) 14.7 kB
# @passkey-fas/webauthn-sdk SDK JavaScript chính thức cho FaS (FIDO2 as Service) Platform - Tích hợp xác thực không mật khẩu dễ dàng [![npm version](https://badge.fury.io/js/@passkey-fas%2Fwebauthn-sdk.svg)](https://www.npmjs.com/package/@passkey-fas/webauthn-sdk) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/) ## 🚀 Tính năng - ✅ **WebAuthn không cần cấu hình** - Không cần hiểu phức tạp về WebAuthn - ✅ **Xác thực không mật khẩu** - Người dùng đăng nhập bằng sinh trắc học/khóa bảo mật - ✅ **Hỗ trợ đa nền tảng** - Hoạt động trên iOS, Android, Windows, macOS - ✅ **React hooks & components** - Tích hợp sẵn cho React.js - ✅ **Vanilla JavaScript** - Hoạt động với mọi website - ✅ **Node.js backend** - JWT validation cho server - ✅ **Hỗ trợ TypeScript** - Bao gồm đầy đủ định nghĩa kiểu - ✅ **Bảo mật mặc định** - Tích hợp sẵn các thực hành bảo mật tốt nhất ## 📦 Cài đặt ```bash npm install @passkey-fas/webauthn-sdk @simplewebauthn/browser ``` ## 🔑 Bắt đầu nhanh Tích hợp dành riêng cho stack hiện tại của bạn: **React + Node.js** ### 1. Thiết lập cho React App (như project FaS của bạn) ```javascript // Giống như trong src/contexts/AuthContext.js của bạn import FaSSDK from '@passkey-fas/webauthn-sdk'; const fas = new FaSSDK({ clientId: process.env.REACT_APP_FAS_CLIENT_ID, clientSecret: process.env.REACT_APP_FAS_CLIENT_SECRET, apiBase: process.env.REACT_APP_FAS_API_BASE }); ``` ### 2. Đăng ký Passkey ```javascript // Đăng ký người dùng mới với passkey const result = await fas.registerPasskey('user@example.com', 'Nguyễn Văn A'); console.log('Người dùng đã đăng ký:', result.user); ``` ### 3. Xác thực ```javascript // Đăng nhập bằng passkey const result = await fas.authenticatePasskey('user@example.com'); console.log('Người dùng đã xác thực:', result.user); // Hoặc đăng nhập không cần mật khẩu (không cần email) const result = await fas.passwordlessLogin(); ``` ## 📚 Tham khảo API ### Constructor ```javascript const fas = new FaSSDK(config) ``` **Tùy chọn cấu hình:** - `clientId` (string, bắt buộc) - Client ID của project bạn - `clientSecret` (string, bắt buộc) - Client secret của project bạn - `apiBase` (string, tùy chọn) - URL cơ sở API (mặc định: production) - `timeout` (number, tùy chọn) - Timeout request tính bằng ms (mặc định: 60000) ### Phương thức #### `registerPasskey(email, fullname?)` Đăng ký passkey mới cho người dùng. ```javascript const result = await fas.registerPasskey('user@example.com', 'Nguyễn Văn A'); // Trả về: { success: true, user: {...}, token: "jwt..." } ``` #### `authenticatePasskey(email)` Xác thực người dùng với passkey đã có. ```javascript const result = await fas.authenticatePasskey('user@example.com'); // Trả về: { success: true, user: {...}, token: "jwt..." } ``` #### `passwordlessLogin()` Xác thực không cần email (sử dụng resident keys). ```javascript const result = await fas.passwordlessLogin(); // Trả về: { success: true, user: {...}, token: "jwt..." } ``` #### `isAuthenticated()` Kiểm tra người dùng đã được xác thực chưa. ```javascript if (fas.isAuthenticated()) { console.log('Người dùng đã đăng nhập'); } ``` #### `getAuthToken()` / `logout()` Lấy token đã lưu hoặc đăng xuất người dùng. ```javascript const token = fas.getAuthToken(); fas.logout(); // Xóa token đã lưu ``` ### Phương thức tĩnh #### `FaSSDK.isWebAuthnSupported()` Kiểm tra hỗ trợ WebAuthn của trình duyệt. ```javascript if (FaSSDK.isWebAuthnSupported()) { // Hiển thị tùy chọn passkey } else { // Hiển thị phương án dự phòng } ``` ## ⚛️ Tích hợp React (Framework chính của bạn) SDK được thiết kế đặc biệt cho React applications như project FaS của bạn: ### Hai cách sử dụng: 1. **Full Components** (`@passkey-fas/webauthn-sdk/react`) - Ready-to-use components 2. **Custom Integration** (`@passkey-fas/webauthn-sdk/react-simple`) - Hooks only cho flexibility ### useFaSAuth Hook ```javascript // Full version vi tt ccomponents import { useFaSAuth } from '@passkey-fas/webauthn-sdk/react'; // Hoặc simple version (chỉ có hook) // import { useFaSAuth } from '@passkey-fas/webauthn-sdk/react-simple'; function MyComponent() { const { user, login, register, loading, error, passwordlessLogin } = useFaSAuth({ clientId: process.env.REACT_APP_FAS_CLIENT_ID, clientSecret: process.env.REACT_APP_FAS_CLIENT_SECRET, apiBase: process.env.REACT_APP_FAS_API_BASE }); const handleLogin = async () => { try { await login('user@example.com'); } catch (error) { console.error('Đăng nhập thất bại:', error); } }; const handlePasswordlessLogin = async () => { try { await passwordlessLogin(); } catch (error) { console.error('Đăng nhập không mật khẩu thất bại:', error); } }; if (user) { return <div>Chào mừng, {user.email}!</div>; } return ( <div> <button onClick={handleLogin} disabled={loading}> {loading ? 'Đang đăng nhập...' : 'Đăng nhập bằng Passkey'} </button> <button onClick={handlePasswordlessLogin} disabled={loading}> {loading ? 'Đang đăng nhập...' : 'Đăng nhập nhanh'} </button> </div> ); } ``` ### Components sẵn có ```javascript import { FaSLogin, FaSRegister, FaSWebAuthnSupport } from '@passkey-fas/webauthn-sdk/react'; function App() { return ( <div> {/* Kiểm tra hỗ trợ WebAuthn */} <FaSWebAuthnSupport showDetails={true} /> <FaSRegister clientId={process.env.REACT_APP_FAS_CLIENT_ID} clientSecret={process.env.REACT_APP_FAS_CLIENT_SECRET} apiBase={process.env.REACT_APP_FAS_API_BASE} onSuccess={(result) => console.log('Đã đăng ký:', result)} onError={(error) => console.error('Lỗi:', error)} /> <FaSLogin clientId={process.env.REACT_APP_FAS_CLIENT_ID} clientSecret={process.env.REACT_APP_FAS_CLIENT_SECRET} apiBase={process.env.REACT_APP_FAS_API_BASE} showPasswordless={true} onSuccess={(result) => console.log('Đã đăng nhập:', result)} /> </div> ); } ``` ## 🔐 Xác thực Token Backend Xác thực JWT tokens trên backend của bạn: ```javascript const jwt = require('jsonwebtoken'); function validateFaSToken(token) { try { const decoded = jwt.verify(token, process.env.FAS_JWT_SECRET); return { valid: true, user: { id: decoded.userId, email: decoded.email, projectId: decoded.projectId } }; } catch (error) { return { valid: false, error: error.message }; } } // Express middleware function authenticateToken(req, res, next) { const token = req.headers['authorization']?.split(' ')[1]; if (!token) { return res.status(401).json({ error: 'Yêu cầu token' }); } const validation = validateFaSToken(token); if (!validation.valid) { return res.status(403).json({ error: 'Token không hợp lệ' }); } req.user = validation.user; next(); } ``` ## 🎨 Styling Các React components bao gồm CSS classes tối thiểu để styling: ```css .fas-register-form, .fas-login-form { display: flex; flex-direction: column; gap: 1rem; } .fas-form-group input { padding: 0.75rem; border: 1px solid #ddd; border-radius: 4px; } .fas-register-button, .fas-login-button { padding: 0.75rem 1.5rem; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; } .fas-error { color: #dc3545; font-size: 0.875rem; } ``` ## 🔧 Xử lý lỗi ```javascript try { await fas.registerPasskey(email, fullname); } catch (error) { switch (error.code) { case 'NotAllowedError': console.log('Người dùng hủy hoặc timeout'); break; case 'NotSupportedError': console.log('WebAuthn không được hỗ trợ'); break; case 'InvalidStateError': console.log('Passkey đã tồn tại'); break; default: console.log('Đăng ký thất bại:', error.message); } } ``` ## 📱 Hỗ trợ nền tảng ### **React.js Applications:** - ✅ Create React App - ✅ Vite + React - ✅ Webpack + React - ✅ Next.js (tự động tương thích) ### **Vanilla JavaScript:** - ✅ ES6 Modules (import/export) - ✅ CommonJS (require/module.exports) - ✅ CDN Script tags - ✅ Modern browsers (Chrome 67+, Firefox 60+, Safari 14+) ### **Backend Integration:** - ✅ Express.js - ✅ Node.js 14+ - ✅ JWT validation middleware ## 🎯 Ví dụ ### Vanilla JavaScript ```html <!DOCTYPE html> <html> <head> <script src="https://unpkg.com/@passkey-fas/webauthn-sdk"></script> </head> <body> <button id="register">Đăng ký</button> <button id="login">Đăng nhập</button> <button id="passwordless">Đăng nhập nhanh</button> <script> // Trong production, load config từ server hoặc build process const config = { clientId: 'your-client-id', // Thay bằng client ID thực tế clientSecret: 'your-client-secret', // Thay bằng client secret thực tế apiBase: 'https://fas-l450.onrender.com/api/webauthn' }; const fas = new FaSSDK(config); document.getElementById('register').onclick = async () => { const email = prompt('Nhập email:'); try { await fas.registerPasskey(email); alert('Đăng ký thành công!'); } catch (error) { alert('Đăng ký thất bại: ' + error.message); } }; document.getElementById('login').onclick = async () => { const email = prompt('Nhập email:'); try { await fas.authenticatePasskey(email); alert('Đăng nhập thành công!'); } catch (error) { alert('Đăng nhập thất bại: ' + error.message); } }; document.getElementById('passwordless').onclick = async () => { try { await fas.passwordlessLogin(); alert('Đăng nhập thành công!'); } catch (error) { alert('Đăng nhập thất bại: ' + error.message); } }; </script> </body> </html> ``` ### Express.js Backend (JWT Validation) ```javascript // middleware/fasAuth.js const jwt = require('jsonwebtoken'); const validateFaSToken = (req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; if (!token) { return res.status(401).json({ error: 'No token provided' }); } try { const decoded = jwt.verify(token, process.env.FAS_JWT_SECRET); req.user = { id: decoded.userId, email: decoded.email, projectId: decoded.projectId }; next(); } catch (error) { return res.status(403).json({ error: 'Invalid token' }); } }; // Protected route example app.get('/api/protected', validateFaSToken, (req, res) => { res.json({ message: 'Access granted', user: req.user }); }); ``` ## 🚀 Triển khai Production ### Biến môi trường **⚠️ QUAN TRỌNG:** Không bao giờ hardcode credentials trực tiếp trong code! Luôn sử dụng environment variables. ```bash # React/.env REACT_APP_FAS_CLIENT_ID=your-client-id REACT_APP_FAS_CLIENT_SECRET=your-client-secret REACT_APP_FAS_API_BASE=https://fas-l450.onrender.com/api/webauthn # Node.js Backend/.env NODE_ENV=production FAS_JWT_SECRET=your-jwt-secret-for-validation PORT=5000 # Backend (for token validation) FAS_JWT_SECRET=your-jwt-secret-from-fas-platform ``` **Lý do sử dụng environment variables:** - 🔒 **Bảo mật:** Tránh expose credentials trong source code - 🔄 **Flexibility:** Dễ dàng thay đổi config cho các môi trường khác nhau - 👥 **Team work:** Mỗi developer có thể có config riêng - 🚀 **Deployment:** Khác nhau giữa dev/staging/production **Alternative config approaches:** ```javascript // 1. Config file (không commit file có credentials thật) import config from './config/fas.config.js'; const fas = new FaSSDK(config); // 2. Runtime từ API const config = await fetch('/api/config').then(r => r.json()); const fas = new FaSSDK(config); // 3. Custom hook với validation function useFaSConfig() { const clientId = process.env.REACT_APP_FAS_CLIENT_ID; const clientSecret = process.env.REACT_APP_FAS_CLIENT_SECRET; if (!clientId || !clientSecret) { throw new Error('FaS credentials not configured'); } return { clientId, clientSecret }; } ``` ### Security Best Practices 1. **HTTPS Required** - WebAuthn only works over HTTPS 2. **Domain Validation** - Add your domain to allowed origins in FaS dashboard 3. **Token Validation** - Always validate JWT tokens on your backend 4. **Rate Limiting** - Implement rate limiting for auth endpoints 5. **Error Handling** - Don't expose sensitive errors to users ## 🌐 API Endpoints SDK sử dụng các endpoint sau từ FaS Platform: - `POST /api/webauthn/public-register/start` - Bắt đầu đăng ký passkey - `POST /api/webauthn/public-register/finish` - Hoàn tất đăng ký passkey - `POST /api/webauthn/public-authenticate/start` - Bắt đầu xác thực passkey - `POST /api/webauthn/public-authenticate/finish` - Hoàn tất xác thực passkey ## 📄 License MIT License - see [LICENSE](LICENSE) file for details. ## 🆘 Support - 📧 **Email**: support@fas-platform.com - 📖 **Documentation**: [https://fas-l450.onrender.com/docs](https://fas-l450.onrender.com/docs) - 🐛 **Issues**: [GitHub Issues](https://github.com/fas-platform/webauthn-sdk/issues) - 💬 **Community**: [Discord](https://discord.gg/fas-platform) --- **Made with ❤️ by FaS (FIDO2 as Service) Platform**