@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
Markdown
# @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
[](https://www.npmjs.com/package/@passkey-fas/webauthn-sdk)
[](https://opensource.org/licenses/MIT)
[](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 với tất cả components
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**