Auth0 đã là một trong những nền tảng định danh phổ biến nhất trong nhiều năm. Nó trau chuốt, tài liệu tốt, và có thể đưa hầu hết ứng dụng từ con số 0 đến luồng đăng nhập hoạt động trong thời gian rất ngắn.
Nhưng khi ứng dụng phát triển, nhiều đội nhóm bắt đầu tìm kiếm các giải pháp thay thế với chi phí dài hạn thấp hơn, tùy chọn tự lưu trữ, thành phần open-source, và kiểm soát dữ liệu người dùng tốt hơn.
Đó là lúc Ory xuất hiện.
Ory cung cấp một ngăn xếp quản lý định danh và truy cập hiện đại dựa trên các tiêu chuẩn mở như OAuth 2.0, OpenID Connect và WebAuthn. Bạn có thể sử dụng qua Ory Network (SaaS được quản lý) hoặc tự triển khai trên hạ tầng của mình.
Trong hướng dẫn này, chúng tôi sẽ đi qua quy trình di chuyển step-by-step từ Auth0 sang Ory, bao gồm xuất người dùng, thay thế SDK, và những cạm bẫy mà không ai nói cho bạn biết.
Tổng quan di chuyển từ Auth0 sang Ory
Di chuyển từ Auth0 sang Ory cần 5 bước:
- Xuất tài khoản người dùng từ Auth0 qua Management API
- Yêu cầu hash mật khẩu qua ticket hỗ trợ Auth0 (chỉ gói trả phí)
- Thiết lập dự án Ory (Ory Network hoặc tự lưu trữ)
- Nhập danh tính người dùng qua admin API của Ory
- Thay thế Auth0 SDK trong ứng dụng bằng Ory SDK
Auth0 vs Ory: So sánh
Trước khi di chuyển, hãy biết bạn đang đánh đổi điều gì.
Khi nào nên ở lại Auth0: Bạn là đội nhóm nhỏ, tốc độ quan trọng hơn chi phí, bạn không cần tự lưu trữ, và bạn hài lòng trả tiền cho sự tiện lợi.
Khi nào nên chuyển sang Ory: Bạn đang mở rộng vượt quá ~10k MAU, bạn muốn kiểm soát hoàn toàn dữ liệu người dùng, bạn muốn tự lưu trữ (tuân thủ, air-gap, GDPR), hoặc hóa đơn Auth0 của bạn đã trở thành mối quan tâm.
Muốn so sánh chi tiết từng tính năng? Ory duy trì một so sánh chính thức bao gồm các gói giá, hỗ trợ giao thức, tùy chọn triển khai, tính năng tuân thủ và SDK có sẵn:
Đọc phần đó trước nếu bạn vẫn đang quyết định liệu việc di chuyển có phù hợp với tình huống của bạn không. Hướng dẫn này bắt đầu từ thời điểm bạn đã đưa ra quyết định.
Chi phí
Giá Ory Network:
- Miễn phí: Phát triển/kiểm thử
- Growth: Tính phí theo người dùng xác thực hoạt động hàng ngày (aDAU), thường rẻ hơn 5–10x so với Auth0 ở quy mô lớn
- Tự lưu trữ (Giấy phép Doanh nghiệp): Phí cố định, không giới hạn người dùng
Giá Auth0 thay đổi thường xuyên. Vui lòng xác minh giá hiện tại tại auth0.com/pricing trước khi đưa ra bất kỳ quyết định nào.
Chiến lược di chuyển
Bạn có hai tùy chọn đích:
Tùy chọn A: Ory Network (đám mây được quản lý): Tốt nhất nếu bạn muốn tiếp tục được quản lý nhưng thoát khỏi giá Auth0 và khóa vendor. Công việc hạ tầng tối thiểu. Thay đổi mã của bạn chủ yếu chỉ là thay SDK.
Tùy chọn B: Ory tự lưu trữ (Kratos + Hydra): Tốt nhất nếu bạn cần toàn quyền sở hữu dữ liệu, môi trường air-gapped, hoặc yêu cầu tuân thủ. Nhiều thiết lập hơn, nhưng bạn sở hữu mọi thứ.
Bước 1: Xuất người dùng Auth0 của bạn
Auth0 cho phép bạn xuất người dùng qua Management API. Bạn cần một Management API token.
# Get a Management API token (replace YOUR_DOMAIN and credentials)
curl --request POST \
--url https://YOUR_DOMAIN.auth0.com/oauth/token \
--header 'content-type: application/json' \
--data '{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"audience": "https://YOUR_DOMAIN.auth0.com/api/v2/",
"grant_type": "client_credentials"
}'
Sau đó xuất người dùng:
curl --request POST \
--url 'https://YOUR_DOMAIN.auth0.com/api/v2/jobs/users-exports' \
--header 'authorization: Bearer YOUR_MGMT_TOKEN' \
--header 'content-type: application/json' \
--data '{
"connection_id": "YOUR_CONNECTION_ID",
"format": "json",
"fields": [
{"name": "user_id"},
{"name": "email"},
{"name": "name"},
{"name": "email_verified"},
{"name": "created_at"}
]
}'
Kiểm tra trạng thái công việc cho đến khi hoàn tất:
curl --request GET \
--url 'https://YOUR_DOMAIN.auth0.com/api/v2/jobs/YOUR_JOB_ID' \
--header 'authorization: Bearer YOUR_MGMT_TOKEN'
Tình huống hash mật khẩu (Đọc kỹ phần này)
Auth0 không bao gồm hash mật khẩu trong xuất hàng loạt tiêu chuẩn. Tuy nhiên, có hai hướng để tiến hành:
Hướng A - Yêu cầu hash (chỉ gói Auth0 trả phí):
Khách hàng trả phí Auth0 có thể yêu cầu xuất hash mật khẩu bằng cách mở ticket hỗ trợ: Auth0 Dashboard → Get Support → Tickets → View All → Open Ticket → "I have a question regarding my Auth0 account" → "I would like to obtain an export of my tenant password hashes."
Khi Auth0 xử lý yêu cầu, bạn sẽ nhận được một tệp JSON nén với ID người dùng, hash mật khẩu và thông tin liên quan. Nhập chúng bằng trường credentials.password.config.hashed_password của Ory (xem Bước 3).
Hướng B - Di chuyển nhẹ nhàng (tất cả gói):
Nhập tài khoản người dùng mà không có mật khẩu, sau đó sử dụng Password Migration Hook của Ory để di chuyển người dùng một cách lười biếng vào lần đăng nhập tiếp theo của họ. Họ xác thực với Auth0 một lần nữa, và Ory tiếp quản từ thời điểm đó.
Người dùng Auth0 gói miễn phí không thể truy cập xuất hash và phải sử dụng Hướng B.
Bước 2: Thiết lập Ory
Tùy chọn A: Ory Network
# Install the Ory CLI — Linux/macOS via the official install script:
curl https://raw.githubusercontent.com/ory/meta/master/install.sh | sh -s ory
sudo mv ./ory /usr/local/bin/
# macOS users can alternatively use Homebrew:
# brew install ory/tap/cli
# Login or create an account
ory auth
# Create a new project
ory create project --name "my-app"
# Get your workspace and project IDs (needed for config commands)
ory list workspaces
ory list projects --workspace <workspace-id>
URL SDK của bạn sẽ giống như: https://yourproject.projects.oryapis.com
Tùy chọn B: Tự lưu trữ
Lưu ý phiên bản: Luôn xác minh tag image ổn định latest tại changelog.ory.com trước khi triển khai. Sử dụng
latestổn cho đánh giá; gắn vào một tag đã xác minh cụ thể trong sản xuất.
Đối với sản xuất, sử dụng PostgreSQL thay vì SQLite:
# docker-compose.yml (production excerpt)
services:
postgres:
image: postgres:15
environment:
POSTGRES_USER: kratos
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} # use .env, never hardcode
POSTGRES_DB: kratos
volumes:
- pgdata:/var/lib/postgresql/data
kratos:
image: oryd/kratos:latest # replace with the current pinned tag from changelog.ory.com
environment:
- DSN=postgres://kratos:${POSTGRES_PASSWORD}@postgres:5432/kratos?sslmode=disable
volumes:
pgdata:
Bước 3: Nhập người dùng vào Ory
API quản trị của Ory Kratos hỗ trợ cả tạo danh tính đơn lẻ (POST /admin/identities) và nhập hàng loạt thực sự (PATCH /admin/identities). Đối với di chuyển lớn, sử dụng endpoint batch. Nó chấp nhận nhiều danh tính mỗi yêu cầu, xử lý lỗi một phần một cách nhẹ nhàng, và trả về kết quả theo từng danh tính tương quan bởi patch_id.
Lưu ý về Schema ID: Các dự án Ory Network mới sử dụng
"preset://email"làmschema_idmặc định. Các dự án tự lưu trữ có thể sử dụng giá trị khác. Kiểm tradefault_schema_idcủa bạn trong cấu hình Ory Identity. Schemapreset://emailchỉ cho phépadditionalProperties: false), vì vậy dữ liệu tên được lưu trữ trongmetadata_publicbên dưới. Nếu schema của bạn bao gồm các trường tên, bạn có thể di chuyển chúng vàotraitstrực tiếp.
// import-users.js
const axios = require('axios');
const fs = require('fs');
const { randomUUID } = require('crypto'); // Node.js 14.17+
const KRATOS_ADMIN = process.env.KRATOS_ADMIN_URL || 'http://localhost:4434';
const ORY_API_KEY = process.env.ORY_API_KEY || '';
// Ory Network default: "preset://email"
// Self-hosted: match your configured default_schema_id (e.g. "default")
const SCHEMA_ID = process.env.ORY_SCHEMA_ID || 'preset://email';
const auth0Users = JSON.parse(fs.readFileSync('./auth0-export.json', 'utf8'));
function buildIdentityPatch(auth0User) {
return {
patch_id: randomUUID(), // correlates each entry in the response back to this input
create: {
schema_id: SCHEMA_ID,
state: 'active',
traits: {
email: auth0User.email,
// Note: preset://email has additionalProperties: false — only email is allowed.
// If your schema includes name fields, add them here:
// name: { first: auth0User.name?.split(' ')[0], last: auth0User.name?.split(' ').slice(1).join(' ') }
},
verifiable_addresses: [
{
value: auth0User.email,
verified: auth0User.email_verified,
via: 'email',
status: auth0User.email_verified ? 'completed' : 'pending',
},
],
// Preserve Auth0 ID and display name for reference during transition
metadata_public: {
auth0_id: auth0User.user_id,
name: auth0User.name || '',
migrated_at: new Date().toISOString(),
},
},
};
}
async function importBatch(patches) {
const headers = { 'Content-Type': 'application/json' };
if (ORY_API_KEY) headers['Authorization'] = `Bearer ${ORY_API_KEY}`;
const { data } = await axios.patch(
`${KRATOS_ADMIN}/admin/identities`,
{ identities: patches },
{ headers }
);
return data.identities; // [{ action, patch_id, identity (UUID string) | error }]
}
async function importAll() {
const batchSize = 50; // reduce to 20–25 if you hit 504 timeouts
const results = [];
for (let i = 0; i < auth0Users.length; i += batchSize) {
const batch = auth0Users.slice(i, i + batchSize);
const patches = batch.map(buildIdentityPatch);
// Map patch_id → email so we can correlate results back to the input user
const patchIdToEmail = new Map(patches.map((p, idx) => [p.patch_id, batch[idx].email]));
try {
const batchResults = await importBatch(patches);
for (const r of batchResults) {
const email = patchIdToEmail.get(r.patch_id) || r.patch_id;
if (r.action === 'create') {
console.log(`✅ Imported: ${email} → Ory ID: ${r.identity}`);
results.push({ success: true, email, oryId: r.identity });
} else {
const reason = r.error?.reason || r.error?.message || 'unknown error';
console.error(`❌ Failed: ${email} — ${reason}`);
results.push({ success: false, email, error: r.error });
}
}
} catch (err) {
console.error(`❌ Batch ${i}–${i + batchSize} failed:`, err.response?.data || err.message);
}
await new Promise(r => setTimeout(r, 200)); // brief pause between batches
}
const succeeded = results.filter(r => r.success).length;
const failed = results.filter(r => !r.success).length;
console.log(`\nImport complete: ${succeeded} succeeded, ${failed} failed`);
fs.writeFileSync('./import-results.json', JSON.stringify(results, null, 2));
}
importAll();
Chạy nó:
KRATOS_ADMIN_URL=https://yourproject.projects.oryapis.com \
ORY_API_KEY=your-ory-api-key \
node import-users.js
Nếu bạn có hash mật khẩu từ Auth0: thêm một khối credentials bên trong mỗi đối tượng create:
"credentials": {
"password": {
"config": {
"hashed_password": "$2a$10$..."
}
}
}
Ory hỗ trợ BCrypt, Argon2, MD5, SHA, PBKDF2, SCrypt, và nhiều hơn nữa — không cần băm lại cho hầu hết các xuất Auth0.
Bước 4: Thay thế SDK trong ứng dụng của bạn
Auth0 SDK (trước):
const { auth, requiresAuth } = require('express-openid-connect');
app.use(auth({
authRequired: false,
auth0Logout: true,
secret: process.env.AUTH0_SECRET,
baseURL: 'http://localhost:3000',
clientID: process.env.AUTH0_CLIENT_ID,
issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
}));
app.get('/profile', requiresAuth(), (req, res) => {
res.json(req.oidc.user);
});
Ory SDK (sau):
const { FrontendApi, Configuration } = require('@ory/client-fetch');
const ory = new FrontendApi(new Configuration({
basePath: process.env.ORY_SDK_URL,
credentials: 'include',
}));
const requireAuth = async (req, res, next) => {
try {
const session = await ory.toSession({ cookie: req.headers.cookie });
req.user = session.identity;
next();
} catch {
res.redirect('/login');
}
};
app.get('/profile', requireAuth, (req, res) => {
res.json(req.user.traits);
});
Thay đổi biến môi trường:
# Remove:
AUTH0_SECRET=...
AUTH0_CLIENT_ID=...
AUTH0_DOMAIN=...
# Add:
ORY_SDK_URL=https://yourproject.projects.oryapis.com
Bước 5: Di chuyển kết nối xã hội
Tùy chọn A: Ory Network
Đối với Ory Network, các nhà cung cấp xã hội được cấu hình qua giao diện Ory Console hoặc Ory CLI, không phải bằng cách chỉnh sửa tệp cấu hình trực tiếp.
Qua Console (dễ nhất cho các nhà cung cấp phổ biến như Google và GitHub):
- Đi đến dự án của bạn tại console.ory.sh
- Điều hướng đến Authentication → Social Sign-In (OIDC)
- Bật nút Enable OpenID Connect và đặt base redirect URI của bạn
- Nhấp Add new OpenID Connect provider, chọn nhà cung cấp của bạn, và nhập Client ID và Secret từ bảng điều khiển nhà phát triển của nhà cung cấp
Qua Ory CLI (có thể viết script, tốt cho tự động hóa):
# Pull the current identity config for your project
ory get identity-config \
--project <project-id> \
--workspace <workspace-id> \
--format yaml > identity-config.yaml
Chỉnh sửa identity-config.yaml để thêm các nhà cung cấp của bạn dưới methods.oidc:
methods:
oidc:
config:
base_redirect_uri: https://your-app.example.com # your app's base URL, NOT the Ory project URL
providers:
- id: google # used in the OAuth callback URL — do NOT change after first login
provider: google
label: Google
client_id: YOUR_GOOGLE_CLIENT_ID
client_secret: YOUR_GOOGLE_CLIENT_SECRET
scope:
- email
- profile
mapper_url: base64://YOUR_BASE64_ENCODED_JSONNET
enabled: true
- id: github # used in the OAuth callback URL — do NOT change after first login
provider: github
label: GitHub
client_id: YOUR_GITHUB_CLIENT_ID
client_secret: YOUR_GITHUB_CLIENT_SECRET
scope:
- user:email
mapper_url: base64://YOUR_BASE64_ENCODED_JSONNET
enabled: true
Sau đó áp dụng các thay đổi:
ory update identity-config \
--project <project-id> \
--workspace <workspace-id> \
--file identity-config.yaml
Tùy chọn B: Tự lưu trữ
Đối với Kratos tự lưu trữ, thêm nhà cung cấp trực tiếp vào kratos/config.yml dưới selfservice.methods.oidc:
selfservice:
methods:
oidc:
enabled: true
config:
providers:
- id: google
provider: google
client_id: YOUR_GOOGLE_CLIENT_ID
client_secret: YOUR_GOOGLE_CLIENT_SECRET
scope:
- email
- profile
mapper_url: base64://YOUR_JSONNET_MAPPER
- id: github
provider: github
client_id: YOUR_GITHUB_CLIENT_ID
client_secret: YOUR_GITHUB_CLIENT_SECRET
scope:
- user:email
mapper_url: base64://YOUR_JSONNET_MAPPER
Người dùng xã hội từ Auth0 sẽ sử dụng "Đăng nhập bằng Google/GitHub" như trước. Ory create danh tính mới khi đăng nhập lần đầu. Ánh xạ bằng email để liên kết với tài khoản hiện có.
5 Cạm bẫy Không Ai Nói Cho Bạn
1. Tình huống hash mật khẩu: Xem Bước 1 ở trên. Lên kế hoạch di chuyển nhẹ nhàng hoặc yêu cầu hash qua ticket hỗ trợ.
2. Khác biệt định dạng token: Auth0 sử dụng JWT với các claim tùy chỉnh. Ory Hydra phát hành token OAuth2 tuân thủ tiêu chuẩn. Nếu API của bạn xác thực token trực tiếp, hãy cập nhật logic xác thực của bạn.
3. Auth0 Rules / Actions không có tương đương trực tiếp: Actions sau đăng nhập của Auth0 (JavaScript tùy chỉnh) ánh xạ tới Ory Actions. Ghi lại mọi action trước khi di chuyển và xây dựng các handler Ory Actions tương đương.
4. Claim sub sẽ thay đổi: ID duy nhất của mỗi người dùng sẽ là một UUID mới trong Ory. Nếu bạn lưu trữ ID người dùng Auth0 trong cơ sở dữ liệu của mình, bạn cần một bảng ánh xạ trong quá trình chuyển đổi. Trường metadata_public.auth0_id được đặt trong quá trình nhập là cầu nối của bạn.
5. CORS nghiêm ngặt hơn trong Ory: Ory yêu cầu cấu hình nguồn gốc được phép rõ ràng. Xác minh serve.public.cors.allowed_origins trong cấu hình Kratos của bạn khớp chính xác với tên miền ứng dụng của bạn.
Kế hoạch di chuyển theo giai đoạn (Triển khai Zero-Downtime)
- Nhập người dùng vào Ory mà không chạm vào ứng dụng trực tiếp của bạn
- Chạy song song cả hai — đăng ký mới đi đến Ory, người dùng hiện tại vẫn sử dụng Auth0
- Di chuyển lười biếng người dùng hiện tại qua đặt lại mật khẩu hoặc hook di chuyển vào lần đăng nhập tiếp theo
- Chuyển ứng dụng của bạn sang Ory SDK khi >90% người dùng hoạt động đã được di chuyển
- Giữ tenant Auth0 hoạt động trong 30–60 days tuần sau cutover như một lưới an toàn
- Ngừng sử dụng Auth0 khi bạn đã tự tin
Kết luận
Di chuyển từ Auth0 sang Ory không phải chuyện nhỏ - hãy dự trù 1–2 sprint cho một ứng dụng sản xuất. Nhưng lợi ích là thực sự: chi phí thấp hơn ở quy mô lớn, toàn quyền sở hữu dữ liệu, và khả năng tự lưu trữ nếu bạn cần.
Tài nguyên:
- Bắt đầu dự án Ory Network miễn phí
- Tài liệu di chuyển chính thức của Ory
- Nhập danh tính & Tham khảo Password Migration Hook
Auth0 Auth0 Alternative Authentication IAM Migrate Auth0 to Ory Open source open source identity management Ory Ory Network Migration




