Как перейти с Auth0 на Ory
Auth0 уже много лет является одной из самых популярных платформ для идентификации. Она хорошо продумана, снабжена подробной документацией и позволяет за очень короткое время превратить большинство приложений в полноценные системы авторизации.
Но по мере роста приложений многие команды начинают искать альтернативы, которые предполагают более низкие долгосрочные затраты, возможность самостоятельного хостинга, использование компонентов с открытым исходным кодом и больший контроль над пользовательскими данными.
Именно здесь на помощь приходит Ory.
Ory предоставляет современный стек управления идентификацией и доступом, основанный на открытых стандартах, таких как OAuth 2.0, OpenID Connect и WebAuthn. Вы можете использовать его через Ory Network (управляемый SaaS) или развернуть самостоятельно в своей инфраструктуре.
В этом руководстве мы расскажем о пошаговой миграции с Auth0 на Ory, включая экспорт данных пользователей, замену SDK и подводные камни, о которых вам никто не расскажет.
Миграция с Auth0 на Ory: обзор
Миграция с Auth0 на Ory состоит из 5 этапов:
- Экспортируйте учетные записи пользователей из Auth0 с помощью API управления
- Запросите хеши паролей через службу поддержки Auth0 (только для платных тарифных планов)
- Настройте проект Ory (в сети Ory или на собственном хостинге)
- Импортируйте идентификационные данные пользователей с помощью API администратора Ory
- Замените SDK Auth0 в своем приложении на SDK Ory
Auth0 против Ory: сравнение
Прежде чем переходить на новую платформу, узнайте, чем вы торгуете.
| Особенность | Auth0 | Ory |
|---|---|---|
| Скорость настройки | ✅ Очень быстрый | ⚠️ Более крутая кривая |
| Управляемое облако | ✅ Да | ✅ Да (Ory Network) |
| Возможность самостоятельного размещения | ❌ Нет | ✅ Да |
| Открытый исходный код | ❌ Нет | ✅ Да |
| Владение пользовательским интерфейсом | ⚠️ Настраиваемый, но ограниченный | ✅ Полностью автономный |
| OAuth2/OIDC | ✅ | ✅ |
| Вход в социальную сеть | ✅ | ✅ |
| МИД | ✅ | ✅ |
| Ценообразование в масштабе | ❌ Дорогие | ✅ Значительно дешевле |
| Блокировка поставщика | ❌ Высокая | ✅ Низкое |
| Владение данными | ❌ Auth0 хранит ваши данные | ✅ Он принадлежит тебе |
Когда стоит остаться на Auth0: у вас небольшая команда, скорость важнее стоимости, вам не нужен собственный хостинг, и вы готовы платить за удобство.
Когда стоит перейти на Ory: у вас более 10 000 активных пользователей в месяц, вы хотите получить полный контроль над пользовательскими данными, разместить приложение на собственном хостинге (для соблюдения нормативных требований, «воздушного зазора» и GDPR) или у вас возникли проблемы с оплатой услуг Auth0.
Хотите получить полную информацию о функциях? У Ory есть официальное сравнение, в котором указаны уровни цен, поддержка протоколов, варианты развертывания, функции обеспечения соответствия требованиям и доступность SDK:
Прочтите это в первую очередь, если вы все еще сомневаетесь, стоит ли вам переходить на новый язык. В этой статье мы исходим из того, что вы уже приняли решение.
Стоимость
Цены на Ory Network:
- Бесплатно: Разработка/тестирование
- Рост: Цена за активного пользователя, прошедшего аутентификацию в течение дня (aDAU), обычно в 5–10 раз ниже, чем у Auth0 при масштабировании
- Самостоятельное размещение (корпоративная лицензия): Фиксированная плата, неограниченное количество пользователей
Цены на Auth0 часто меняются. Пожалуйста, ознакомьтесь с актуальными тарифами на auth0.com/pricing, прежде чем принимать какие-либо решения.
Стратегия миграции
У вас есть два варианта:
Вариант А: Ory Network (управляемое облако): лучший вариант, если вы хотите, чтобы за вас все делали, но при этом избежать привязки к тарифному плану и сервису Auth0. Минимальные затраты на инфраструктуру. Изменения в коде сводятся в основном к замене SDK.
Вариант Б: Ory на собственном хостинге (Kratos + Hydra): лучший вариант, если вам нужен полный суверенитет данных, изолированная среда или соблюдение нормативных требований. Требуется больше времени на настройку, но все будет в вашем распоряжении.
Шаг 1. Экспорт пользователей Auth0
Auth0 позволяет экспортировать пользователей через API управления. Вам понадобится токен API управления.
# Получить токен API управления (замените YOUR_DOMAIN и учетные данные)
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"
}'
Затем экспортируйте пользователей:
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"}
]
}'
Проверяйте статус задания до его завершения:
curl --request GET \ --url 'https://YOUR_DOMAIN.auth0.com/api/v2/jobs/YOUR_JOB_ID' \ --header 'authorization: Bearer YOUR_MGMT_TOKEN'
Ситуация с хешированием паролей (прочитайте внимательно)
Auth0 не включает хешированные пароли в стандартный пакетный экспорт. Однако есть два возможных решения:
Вариант А — запросить хешированные пароли (только для платных планов Auth0):
Платные клиенты Auth0 могут запросить экспорт хэшей паролей, отправив запрос в службу поддержки: Панель управления Auth0 → Поддержка → Запросы → Посмотреть все → Отправить запрос → «У меня вопрос по поводу моей учетной записи Auth0» → «Я хотел бы получить экспорт хэшей паролей моего клиента».
После обработки запроса Auth0 вы получите сжатый JSON-файл с идентификаторами пользователей, хешированными паролями и сопутствующей информацией. Импортируйте их с помощью поля credentials.password.config.hashed_password в Ory (см. шаг 3).
Путь Б — плавная миграция (все планы):
Импортируйте учетные записи пользователей без паролей, а затем используйте крюк для миграции паролей от Ory, чтобы при следующем входе в систему пользователи могли лениво выполнить миграцию. Они еще раз проходят аутентификацию в Auth0, после чего Ory берет все на себя.
Пользователи бесплатного уровня Auth0 не могут экспортировать хэши и должны использовать путь B.
Шаг 2. Настройка Ory
Вариант A: сеть Ory
# Установите Ory CLI — Linux/macOS с помощью официального установочного скрипта: curl https://raw.githubusercontent.com/ory/meta/master/install.sh | sh -s ory sudo mv ./ory /usr/local/bin/ # Пользователи macOS могут воспользоваться Homebrew: # brew install ory/tap/cli # Войдите в систему или создайте учетную запись ory auth # Создайте новый проект ory create project --name "my-app" # Получите идентификаторы своего рабочего пространства и проекта (необходимы для команд настройки) ory list workspaces
ory list projects --workspace <workspace-id>
URL вашего SDK будет выглядеть так: https://yourproject.projects.oryapis.com
Вариант Б: собственный хостинг
Примечание по версии: перед развертыванием всегда проверяйте последнюю стабильную версию образа по тегу changelog.ory.com. Для тестирования можно использовать
latest; в рабочей среде закрепите образ за конкретным проверенным тегом.
Для продакшена лучше использовать PostgreSQL, а не SQLite:
# docker-compose.yml (выдержка из рабочей версии)
services:
postgres:
image: postgres:15
environment:
POSTGRES_USER: kratos
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} # используйте .env, никогда не прописывайте пароль вручную
POSTGRES_DB: kratos
volumes:
- pgdata:/var/lib/postgresql/data
kratos:
image: oryd/kratos:latest # замените на текущий закрепленный тег из changelog.ory.com
environment:
- DSN=postgres://kratos:${POSTGRES_PASSWORD}@postgres:5432/kratos?sslmode=disable
volumes: pgdata:
Шаг 3. Импорт пользователей в Ory
Административный API Ory Kratos поддерживает как создание отдельных идентификаторов (POST /admin/identities), так и настоящий массовый импорт (PATCH /admin/identities). Для масштабных миграций используйте пакетную конечную точку. Она позволяет отправлять несколько идентификаторов в одном запросе, корректно обрабатывает частичные сбои и возвращает результаты по каждому идентификатору, сопоставленные с patch_id.
Примечание по идентификатору схемы: в новых проектах Ory Network
"preset://email"используется по умолчаниюschema_id. В проектах, размещенных на собственных серверах, может использоваться другое значение. Проверьтеdefault_schema_idв конфигурации Ory Identity. Схемаpreset://emailдопускает использованиеadditionalProperties: false), поэтому данные имени хранятся вmetadata_publicниже. Если в вашей схеме есть поля с именами, вы можете перенести их вtraitsнапрямую.
// 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 по умолчанию: "preset://email"
// При самостоятельном размещении: соответствует настроенному вами default_schema_id (например, "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(), // сопоставляет каждую запись в ответе с исходными данными
create: {
schema_id: SCHEMA_ID,
state: 'active',
traits: {
email: auth0User.email,
// Примечание: в предустановке preset://email параметр additionalProperties имеет значение false — допускается только email.
// Если в вашей схеме есть поля с именами, добавьте их сюда:
// 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 ? 'завершено' : 'ожидает',
},
],
// Сохраняем идентификатор Auth0 и отображаемое имя для справки при переходе
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) | error }]
}
async function importAll() {
const batchSize = 50; // уменьшите до 20–25, если столкнетесь с таймаутами 504
const results = [];
for (let i = 0; i < auth0Users.length; i += batchSize) {
const batch = auth0Users.slice(i, i + batchSize);
const patches = batch.map(buildIdentityPatch);
// Сопоставляем patch_id → email, чтобы можно было сопоставить результаты с исходными данными пользователя
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(`✅ Импортировано: ${email} → Ory ID: ${r.identity}`);
results.push({ success: true, email, oryId: r.identity });
} else {
const reason = r.error?.reason || r.error?.message || 'неизвестная ошибка';
console.error(`❌ Ошибка: ${email} — ${reason}`);
results.push({ success: false, email, error: r.error });
}
}
} catch (err) {
console.error(`❌ Ошибка в пакете ${i}–${i + batchSize}:`, err.response?.data || err.message);
}
await new Promise(r => setTimeout(r, 200)); // короткая пауза между пакетами
}
const succeeded = results.filter(r => r.success).length;
const failed = results.filter(r => !r.success).length;
console.log(`\nИмпорт завершен: ${succeeded} выполнено успешно, ${failed} не выполнено`);
fs.writeFileSync('./import-results.json', JSON.stringify(results, null, 2));
}
importAll();
Запустите его:
KRATOS_ADMIN_URL=https://yourproject.projects.oryapis.com \ ORY_API_KEY=ваш-api-ключ-ory \ node import-users.js
Если у вас есть хэши паролей от Auth0: добавьте блок credentials внутрь каждого объекта create:
"credentials": {
"password": {
"config": {
"hashed_password": "$2a$10$..."
}
}
}
Ory поддерживает алгоритмы BCrypt, Argon2, MD5, SHA, PBKDF2, SCrypt и другие — для большинства экспортируемых данных Auth0 повторное хеширование не требуется.
Шаг 4. Замените SDK в своем приложении
SDK Auth0 (ранее):
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 (после):
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);
});Изменения переменных среды:
# Удалить: AUTH0_SECRET=... AUTH0_CLIENT_ID=... AUTH0_DOMAIN=... # Добавьте: ORY_SDK_URL=https://yourproject.projects.oryapis.com
Шаг 5. Перенос социальных связей
Вариант А: Ory Network
В Ory Network социальные сервисы настраиваются через пользовательский интерфейс Ory Console или Ory CLI, а не путем прямого редактирования конфигурационных файлов.
Через консоль (проще всего для таких популярных сервисов, как Google и GitHub):
- Перейдите в свой проект на console.ory.sh
- Перейдите в раздел Аутентификация → Вход через социальные сети (OIDC)
- Включите переключатель Включить OpenID Connect и укажите базовый URI перенаправления
- Нажмите Добавить нового поставщика OpenID Connect, выберите поставщика и введите идентификатор клиента и секретный ключ из консоли разработчика поставщика
С помощью интерфейса командной строки Ory (с возможностью написания скриптов, подходит для автоматизации):
# Получите текущую конфигурацию идентификатора для вашего проекта
ory get identity-config \ --project <project-id> \ --workspace <workspace-id> \ --format yaml > identity-config.yaml
В разделе identity-config.yaml добавьте своих провайдеров в methods.oidc:
methods:
oidc:
config:
base_redirect_uri: https://your-app.example.com # базовый URL-адрес вашего приложения, А НЕ URL-адрес проекта Ory
providers:
- id: google # используется в URL обратного вызова OAuth — не изменяется после первого входа в систему
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 # используется в URL обратного вызова OAuth — не изменяется после первого входа в систему
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
Затем примените изменения:
ory update identity-config \ --project <project-id> \ --workspace <workspace-id> \ --file identity-config.yaml
Вариант Б: собственный хостинг
Для Kratos с собственным хостингом добавьте провайдеров напрямую в kratos/config.yml в разделе 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: ВАШ_ИДЕНТИФИКАТОР_КЛИЕНТА_GITHUB client_secret: ВАШ_СЕКРЕТНЫЙ_КЛЮЧ_КЛИЕНТА_GITHUB scope: - user:email mapper_url: base64://YOUR_JSONNET_MAPPER
Пользователи Auth0 из социальных сетей будут по-прежнему использовать функцию «Войти через Google/GitHub». Ory создает новые учетные записи при первом входе. Сопоставьте адрес электронной почты с существующими учетными записями.
5 подводных камней, о которых вам никто не расскажет
1. Проблема с хешированием паролей: см. шаг 1 выше. Продумайте плавный переход или запросите хеширование через службу поддержки.
2. Различия в форматах токенов: Auth0 использует JWT с пользовательскими утверждениями. Ory Hydra выдает токены OAuth2, соответствующие стандартам. Если ваш API проверяет токены напрямую, обновите логику проверки.
3. У правил и действий Auth0 нет прямого эквивалента: действия Auth0 после входа в систему (пользовательский JavaScript) сопоставляются с действиями Ory. Перед миграцией задокументируйте каждое действие и создайте эквивалентные обработчики действий Ory.
4. Утверждение sub изменится: уникальный идентификатор каждого пользователя в Ory будет представлять собой новый UUID. Если вы храните идентификаторы пользователей Auth0 в своей базе данных, при переходе на новую систему вам понадобится таблица сопоставления. Поле metadata_public.auth0_id, заданное при импорте, станет вашим связующим звеном.
5. В Ory более строгие требования к CORS: в Ory требуется явная настройка разрешенных источников. Убедитесь, что serve.public.cors.allowed_origins в вашей конфигурации Kratos точно соответствует домену вашего приложения.
Поэтапный план миграции (внедрение без простоев)
- Импортируйте пользователей в Ory, не касаясь вашего live-приложения
- Запускайте оба приложения параллельно — новые регистрации отправляются в Ory, существующие пользователи по-прежнему используют Auth0
- Ленивая миграция существующих пользователей с помощью сброса пароля или подключения к миграции при следующем входе в систему
- Переключите свое приложение на Ory SDK, как только будет перенесено > 90% активных пользователей
- Поддерживайте активность клиента Auth0 в течение 30-60 дней после отключения в качестве подстраховки
- Отключите Auth0, как только будете уверены
Окончательный Вердикт
Переход с Auth0 на Ory — задача не из простых. Для производственного приложения потребуется 1–2 спринта. Но результат того стоит: меньшие затраты при масштабировании, полное владение данными и возможность самостоятельного хостинга, если это когда-нибудь понадобится.
Ресурсы:
- Начните свой проект в Ory Network бесплатно
- Официальная документация по миграции в Ory
- Справочник по импорту идентификаторов и миграции паролей
Редактор: AndreyEx
Важно: Данная статья носит информационный характер. Автор не несёт ответственности за возможные сбои или ошибки, возникшие при использовании описанного программного обеспечения.