Ory Hydraは、Go製・オープンソースのOAuth 2.0/OpenID Connectサーバーです。ユーザーのデータベースもログイン画面も持たず、「誰がログインしたか」は利用者側のアプリが決め、Hydraはトークンの発行と検証だけを受け持ちます。この記事では、2026年10月時点の最新版v26.2.0を手元で起動した実行結果をもとに、仕組み、ログイン・同意・ログアウト画面との連携、つまずきやすいCSRF Cookieのエラー、本番構成で外せない設定、Keycloakとの選び分けを整理します。
まとめ:Ory Hydraの要点
- 役割:OAuth 2.0の認可サーバーとOpenID Connectプロバイダーだけを担う。ユーザー管理・ログイン画面・同意画面は自前で用意するか、同じOryのKratosと組み合わせる
- 最新版:v26.2.0(2026-03-20)。v2.3.0の次がv25.4.0(2025-11-07)で、ここから年と四半期を表すカレンダー方式(YY.Q.B)の版番号に変わった
- 構成:公開用のPublic API(4444番)と管理用のAdmin API(4445番)。Admin APIには認証機能が無いので、外部に出さない
- 自分で作るもの:ログイン画面・同意画面・ログアウト画面・エラー画面。ログイン・同意・ログアウト画面はchallengeを受け取り、サーバー側からAdmin APIのacceptまたはrejectを呼ぶ。エラー画面は受け取ったエラー情報を表示する
- つまずきやすい点:「No CSRF value available in the session cookie」は、Cookieが届いていないときに出る。ホスト名の混在と、本番モードでのhttp接続が典型的な原因
- ライセンス:Apache-2.0。マネージド版はOry Network(有料は年$770から)
- 向かない場面:ユーザー管理画面やLDAP連携まで箱から出して使いたいなら、全部入りのKeycloakのほうが早い
Ory Hydraの位置づけ:ユーザーDBを持たない認可サーバー
OAuth 2.0の認可サーバーは、クライアントの登録、認可コードやトークンの発行、失効、署名鍵の管理を担います。Hydraはこの部分だけを実装し、パスワードの照合や会員情報の保存を持ちません。GitHubリポジトリの説明文では「integrates with your user management through headless APIs」と説明されています。既に会員DBとログイン画面がある事業者が、その上に「他社アプリにAPIアクセスを許可する仕組み」や社内のSSOを追加するときに向いた作りです。
OAuth 2.0そのものの流れはOAuth 2.0の仕組みと認可フローの解説、IDトークンの検証手順はOIDC(OpenID Connect)の解説にまとめています。
Oryの製品群とHydraの担当範囲
「ory」で検索するとHydra以外の製品も出てきます。Oryは同じ版番号で複数のサーバーを出しており、2026-03-20(UTC)に次の5製品がそろってv26.2.0になりました。
| 製品 | 担当 |
|---|---|
| Ory Hydra | OAuth 2.0/OIDCのトークン発行 |
| Ory Kratos | ユーザー登録・ログイン・MFA |
| Ory Keto | 権限判定(Zanzibar型) |
| Ory Oathkeeper | APIの手前で認証・認可するプロキシ |
| Ory Polis | SAML/OIDCのエンタープライズSSO |
Hydraにログイン機能を足したいならKratos、APIの手前でトークンを検証したいならOathkeeper、という分担です。すべてを入れる必要はなく、Hydra単体でも既存のログイン画面とつなげば動きます。
対応グラントタイプと実装済みの標準仕様
v26.2.0を起動して /.well-known/openid-configuration を取得すると、grant_types_supported は次の5つでした。
["authorization_code", "implicit", "client_credentials", "refresh_token",
"urn:ietf:params:oauth:grant-type:device_code"]
クライアント認証方式(token_endpoint_auth_methods_supported)は client_secret_post・client_secret_basic・private_key_jwt・none の4つです。none はPKCEを使う公開クライアント(SPAやモバイル)向けです。デバイスフロー(RFC 8628)はv25.4.0で入り、同じ版でOAuth 2.0のメタデータ /.well-known/oauth-authorization-server(RFC 8414)も返すようになりました。
READMEはほかに、Dynamic Client Registration(RFC 7591)、JWT Profile(RFC 7523)、Token Introspection(RFC 7662)を実装済みとして挙げています。OpenID Foundationの認定はBasic OP・Implicit OP・Hybrid OP・Config OP・Dynamic OPの5プロファイルです(取得はv1.0.0時点)。
MCPの認可仕様(2025-11-25版)が認可サーバーに対応を推奨(SHOULD)しているCIMD(Client ID Metadata Documents)は、v26.2.0の時点で未対応です。2026-01-17に起票された対応要望のissue #4061は、2026-10-23時点でも開いたままです。CIMDの仕組みはCIMD(Client ID Metadata Documents)の解説を参照してください。
v2.3.0・v25.4.0・v26.2.0の変更点と版番号の変遷
国内の解説記事の多くはv2.x時代のものです。版番号が2から25へ飛んだのは、2025年11月のリリースでOryが年と四半期を表すカレンダー方式(YY.Q.B)の版番号へ切り替えたためで、中身が20世代進んだわけではありません。
| 版 | 公開日 | 主な変更 |
|---|---|---|
| v2.3.0 | 2025-01-17 | v2系の最終版。リフレッシュトークンの猶予付きローテーション |
| v25.4.0 | 2025-11-07 | デバイスフロー、RFC 8414のメタデータ、同意単位のトークン一括失効 |
| v26.2.0 | 2026-03-20 | Postgresのトランザクション自動再試行、依存の脆弱性対応 |
2026-10-23時点で、v26.2.0より新しいリリースは出ておらず、Docker Hubの oryd/hydra:latest もv26.2.0です。v2系から上げるときは、DBマイグレーションに加えて、PostgreSQLで uuid-ossp 拡張を有効にしておきます(v25.4.0でUUID生成が uuid_generate_v4() に変わったため)。
アーキテクチャ:Public API(4444)とAdmin API(4445)の分離
Hydraは既定で2つのポートを開きます。
- Public API(4444):
/oauth2/auth(認可)、/oauth2/token(トークン)、/userinfo、/oauth2/sessions/logout(ログアウト)、/.well-known/jwks.jsonなど、クライアントとブラウザが叩くエンドポイント - Admin API(4445):クライアントの登録、ログイン・同意・ログアウトリクエストの受理と拒否、トークンのイントロスペクションなど、自社のバックエンドだけが叩くエンドポイント
Oryの本番運用ドキュメントは、Admin APIについて「None of the administrative endpoints have any built-in access control」と明記しています。4445番に届けば、誰でもクライアントを作成でき、どのユーザーのログインでも承認できます。Admin APIはインターネットに出さず、社内ネットワークに閉じるか、APIゲートウェイで認証をかけてください。環境変数 SERVE_ADMIN_HOST に unix:/var/run/hydra/admin_socket を設定すると、Admin APIをUNIXソケットにバインドできます。本番運用ドキュメントには旧名の ADMIN_HOST が載っていますが、v26.2.0で ADMIN_HOST を指定して起動すると、ソケットは作られず全インターフェースの4445番で待ち受けようとしました。
Public API側も、同ドキュメントはAPIゲートウェイかロードバランサーの背後に置き、そこでTLSを終端する構成を強く推奨しています。パスで振り分けるゲートウェイでは、公開ホスト名はそのまま、パスは振り分け用のプレフィックス(例 /hydra/)を除いてHydraへ渡す設定が必要です(challengeの値の計算にホストとパスが使われるため)。
ログイン・同意フローの実装:challengeの取得とacceptによる受理
Hydraを組み込むとき、自社で作るのは次の4つの画面と、Admin APIを呼ぶサーバー側の処理です。
| 設定キー | 画面 | 受け取る値 | 返す先 |
|---|---|---|---|
urls.login |
ログイン | login_challenge |
login accept/reject |
urls.consent |
同意 | consent_challenge |
consent accept/reject |
urls.logout |
ログアウト確認 | logout_challenge |
logout accept/reject |
urls.error |
エラー表示 | error など |
なし |
画面とは別に、どのスコープでどのAPIを守るかというscope体系の設計も自社の仕事です。Hydraはクライアントに許可したscopeの範囲でしかトークンを出しませんが、scopeの名前と意味は決めてくれません。
v26.2.0で認可コードフロー(PKCE付き)を最後まで通したときの流れは次のとおりでした。
- クライアントがブラウザを
/oauth2/auth?client_id=…&code_challenge=…へ送る - Hydraが
urls.loginの画面へ?login_challenge=…を付けてリダイレクトする - ログイン画面が
GET /admin/oauth2/auth/requests/login?login_challenge=…でリクエスト内容を取得する(返るキーはchallenge・client・requested_scope・skip・subjectなど) - ユーザーを自前の方法で認証し、
PUT /admin/oauth2/auth/requests/login/acceptにsubjectを送る。応答のredirect_toへブラウザを戻す - Hydraが
urls.consentの画面へ?consent_challenge=…を付けてリダイレクトする - 同意画面が
requested_scopeを表示し、許可されたらPUT /admin/oauth2/auth/requests/consent/acceptにgrant_scopeを送る。IDトークンに載せたいクレームはsession.id_tokenに入れる - Hydraが
redirect_uriへcode=ory_ac_…を返し、クライアントが/oauth2/tokenで交換する
手順4と6の呼び出しをcurlで示します。LC には手順2で受け取ったlogin_challenge、CC には手順5で受け取ったconsent_challengeをそれぞれ設定し、順番に実行してください。subject・grant_scope・emailは説明用の値なので、認証済みユーザーと実際に許可された内容に置き換えます。ログイン・同意画面のサーバー側で、この2つのHTTPリクエストを送るのが実装の中心です。
curl -s -X PUT -H 'Content-Type: application/json' \
-d '{"subject":"user-123","remember":true,"remember_for":3600}' \
"http://127.0.0.1:4445/admin/oauth2/auth/requests/login/accept?login_challenge=$LC"
curl -s -X PUT -H 'Content-Type: application/json' \
-d '{"grant_scope":["openid","offline_access"],"remember":true,
"session":{"id_token":{"email":"[email protected]"}}}' \
"http://127.0.0.1:4445/admin/oauth2/auth/requests/consent/accept?consent_challenge=$CC"
トークン交換の応答には access_token・id_token・refresh_token が入り、IDトークンの sub はログイン受理で送った user-123、email は同意受理で送った値でした。同じ認可コードをもう一度交換すると invalid_grant(The authorization code has already been used)で拒否されます。手順の意味は認可コードフローの実装手順、code_verifierの作り方はPKCEの解説で詳しく扱っています。
skipフラグとremember:2回目のログインを省く仕組み
ログイン受理で "remember": true を送ると、HydraはブラウザにCookieでセッションを残します。同じブラウザで2回目の認可リクエストを出すと、ログインリクエストの skip が true、subject が user-123 で返りました。同意も "remember": true で受理し、記録が有効な間に同じユーザー・同じクライアントが許可済み範囲のscopeを要求した場合は、同意リクエストの skip も true になります。
skip が true のときは、画面を出さずにそのままacceptを返すのが正しい実装です。ここでパスワード入力画面を出すと、SSOのつもりが毎回ログインを求める作りになります。skip はHydraが発行したCookieで判定されるため、ブラウザがそのCookieを送らない状況(Cookieの削除、別ブラウザ)では毎回 false になります。複数のアプリで1回のログインを使い回す設計の全体像はSSO(シングルサインオン)の実現方式の解説で扱っています。
prompt=login・max_age・prompt=noneによるskip判定の違い
クライアントが認可リクエストに付けるOIDCのパラメータで、skip の値が変わります。ログイン済み・同意済みのブラウザで試した結果は次のとおりです。
| 認可リクエスト | login skip | consent skip |
|---|---|---|
| パラメータなし(2回目) | true | true |
prompt=login |
false | true |
max_age=1(3秒後) |
false | true |
prompt=none(未ログイン) |
画面に来ずにエラーで戻る | |
prompt=login と、前回のログインから max_age 秒を過ぎたリクエストでは、Cookieが残っていてもHydraは skip=false を返し、subject も空にします。送金や設定変更の前にパスワードを入れ直させたいクライアントは、この2つで再認証を要求できます。同意の skip は別管理で、ログインをやり直させても true のままでした。
prompt=none は画面を一切出さずにログイン状態を確かめるためのパラメータで、セッションが無いとログイン画面を経由せず、redirect_uri へ error=login_required(Prompt ‘none’ was requested, but no existing login session was found.)が返ります。同意が無い場合は consent_required です(v26.2.0のconsent/strategy_default.go)。
skip_consentで同意画面を省くときの注意
自社のアプリのように同意画面を見せる必要が無いクライアントには、skip_consent: true を設定できます。ただし、v26.2.0でこのクライアントを試すと、同意リクエストの skip は false で返り、Hydraは同意画面へリダイレクトしてきました。v26.2.0のソースでは、この項目はクライアントの保存と検証にしか使われておらず、同意を自動で済ませる処理は同意画面の側にあります。
公式のサンプル画面(hydra-login-consent-nodeのconsent.ts)は、consentRequest.skip か client.skip_consent のどちらかが真なら画面を出さずにacceptしています。自作の同意画面でも、同意リクエストに含まれる client.skip_consent を見てacceptする分岐を入れてください。ログアウトの確認画面を省く skip_logout_consent も同じ扱いです。どちらもAdmin APIからしか設定できず、Dynamic Client Registrationで指定するとエラーになります。
既存のLDAP・Active Directoryとつなぐ方法
HydraにはLDAP連携の機能がありません。ログイン画面のサーバーがLDAPやActive Directoryへbindしてパスワードを照合し、成功したらその識別子を subject としてacceptに渡します。subject にはメールアドレスのように変わりうる値ではなく、社員番号や、ADのobjectGUID・OpenLDAPのentryUUIDのような不変の識別子を使ってください。IDトークンの sub はクライアント側でユーザーの主キーとして保存されるため、後から変えると別人扱いになります。
ログアウトの実装:logout_challengeとpost_logout_redirect_uri
ログアウトもログインと同じく、Hydraがchallengeを付けて自社の画面へ渡す方式です。RP-Initiated Logout・Front-Channel Logout・Back-Channel Logoutの3つに対応しています(OryのOpenID Connect logoutドキュメント)。v26.2.0で、クライアント起点のログアウトを通した手順は次のとおりでした。
- クライアントがブラウザを
/oauth2/sessions/logout?id_token_hint=…&post_logout_redirect_uri=…&state=…へ送る - Hydraが
urls.logoutの画面へ?logout_challenge=…を付けてリダイレクトする - ログアウト画面が
GET /admin/oauth2/auth/requests/logout?logout_challenge=…で内容を取得する(subject・sid・client・rp_initiatedなどが返る) - 確認後に
PUT /admin/oauth2/auth/requests/logout/acceptを呼ぶと、logout_verifier付きのURLが返る。そこへブラウザを戻す - Hydraがセッションを消し、
post_logout_redirect_uriへstateを付けて戻す
post_logout_redirect_uri は、クライアント登録時の post_logout_redirect_uris に入れた値でないと使えません。Oryのドキュメントは、どのセッションを終わらせるかをHydraが判断できるよう、id_token_hint を常に付けることを勧めています。
ログアウトの後、同じブラウザで認可リクエストを出すと、ログインの skip は false に戻りました。一方、同意の skip は true のままでした。ログアウトで消えるのはログインのセッションで、「このクライアントにこのscopeを許可した」という記録は残ります。同意をやり直させたい場合は、Admin APIの DELETE /admin/oauth2/auth/sessions/consent で同意を取り消します。
エラーの返し方とCSRF Cookieのトラブル
rejectによるクライアントへのエラー応答
ログインに失敗させたい、ユーザーが同意を拒んだ、という場合はacceptの代わりにrejectを呼びます。
curl -s -X PUT -H 'Content-Type: application/json' \
-d '{"error":"access_denied","error_description":"The resource owner denied the request"}' \
"http://127.0.0.1:4445/admin/oauth2/auth/requests/login/reject?login_challenge=$LC"
応答の redirect_to へブラウザを戻すと、クライアントの redirect_uri に error=access_denied&error_description=The+resource+owner+denied+the+request&state=… が付いて返りました。同意の拒否は /consent/reject、ログアウトの取りやめは /logout/reject で、ログアウトのrejectは204の空応答を返すため、その後の遷移先はログアウト画面の側で決めます。認可リクエストの redirect_uri が登録外のように、クライアントへ戻すこと自体が危ないエラーは、urls.error の画面へ送られます。
パスワードを間違えただけのときにrejectすると認可フローそのものが終わるので、その場合はログイン画面にエラーを出して再入力させ、rejectはユーザーがキャンセルしたときや、アカウントが停止されているときに使います。
Hydraは、ログイン画面へ送る前と同意画面へ送る前にCSRF用のCookieをブラウザへ発行し、受理後に戻ってきたリクエストでそのCookieを照合します。これは自作画面のフォームに対するCSRF対策を代替しないため、ログイン・同意画面側でもCSRFトークンを検証します。v26.2.0で同じブラウザから取得したCookieは次の3つでした(--dev 付きで起動したため _dev が付いています)。
ory_hydra_login_csrf_dev_3567479735
ory_hydra_consent_csrf_dev_3567479735
ory_hydra_session_dev
末尾の数字はクライアントIDのmurmur3ハッシュで、同じブラウザで複数のクライアントのフローを並行させても混ざらないようにするためのものです。Cookieを持たない状態でログイン受理後の redirect_to を開くと、redirect_uri に error=request_forbidden と「The request is not allowed. No CSRF value available in the session cookie.」が返りました。OryのCommon CSRF pitfallsが挙げる原因のうち、v26.2.0で確かめたものは次のとおりです。
- ホスト名の混在:
localhost:4444で認可を始めると、Cookieはlocalhostに付きます。一方、acceptが返すredirect_toはurls.self.issuerのホスト(例127.0.0.1:4444)なので、Cookieが送られず同じエラーになりました。クライアントの認可URLとissuerのホスト名をそろえます - 本番モードでのhttp:
--devを付けないと、HydraはCookieに必ずSecure属性を付けます(driver/config/provider.go)。TLSをゲートウェイで終端していても、ブラウザから見てhttpなら Cookie は送られません - SameSiteとiframe:
serve.cookies.same_site_modeをNoneにしないと、別サイトのiframeからはCookieが送られません。Noneはhttpsのissuerでしか効かず、httpのissuerではLaxに置き換えられます
同じドキュメントは、リバースプロキシがCookieヘッダーを落としている場合や、パスの書き換えをしている場合も原因になると書いています。ブラウザの開発者ツールで、redirect_to へのリクエストに ory_hydra_login_csrf_… が載っているかを先に確かめると、原因を絞り込めます。
Cookieのドメインと名前は serve.cookies.domain・serve.cookies.names で変えられます(Configuring cookies)。ログイン画面とHydraが別のサブドメインでも、通常はHydraのCookieを共有する必要はありません。ブラウザがHydraへ戻る際にCookieを送信できればよく、親ドメインへの拡張は共有が必要な設計に限ります。
Hydraを手元で起動する手順(v26.2.0)
GitHubのリリースにはOS別のバイナリがあり、SQLiteを含むビルド(名前に sqlite が付くもの)を選べば、DBを用意せずに試せます。以下はmacOS用 hydra_26.2.0-macOS_sqlite_64bit.tar.gz で実行した手順です。
設定ファイルとsecrets.systemの16文字制約
次の内容を作業ディレクトリの hydra.yml に保存します。
serve:
cookies:
same_site_mode: Lax
urls:
self:
issuer: http://127.0.0.1:4444
login: http://127.0.0.1:3000/login
consent: http://127.0.0.1:3000/consent
logout: http://127.0.0.1:3000/logout
error: http://127.0.0.1:3000/error
post_logout_redirect: http://127.0.0.1:3000/logged-out
secrets:
system:
- thisIsADevSecretOfAtLeast32Chars!!
secrets.system は機密データのAES-GCM暗号化とHMAC署名に使う鍵で、16文字未満だと起動に失敗します。5文字の値で起動したときのエラーは次のとおりでした。
Error: I[#/secrets/system/0] S[#/properties/secrets/properties/system/items/minLength] length must be >= 16, but got 5
本番では openssl rand -base64 32 などで生成した値を使い、secrets.cookie と secrets.pagination も個別に設定するよう、Oryの本番運用ドキュメントが求めています。secrets.system は配列で、先頭が署名・暗号化に使われ、リスト全体が署名検証・復号に使われます。鍵を入れ替えるときは新しい値を先頭に追加し、古い値を後ろに残します。
マイグレーションと起動(httpsが必須になる条件)
tar -xzf hydra_26.2.0-macOS_sqlite_64bit.tar.gz
mkdir -p /tmp/hydra
export DSN='sqlite:///tmp/hydra/db.sqlite?_fk=true&mode=rwc'
./hydra migrate -c hydra.yml sql up -e --yes
./hydra serve -c hydra.yml all --dev --sqa-opt-out
serve all はPublicとAdminの両方を起動します。--dev を外すと、urls.self.issuer がhttpのままでは「issuer URL scheme must be HTTPS unless development mode is enabled」で起動しません。ローカル検証だけ --dev を付け、本番はissuerをhttpsのURLにします。--sqa-opt-out は、起動時に「Software quality assurance features are enabled」と出る匿名の利用統計の送信を止めるオプションです。
クライアント登録とトークン発行の確認
./hydra create client --endpoint http://127.0.0.1:4445 \
--grant-type client_credentials --scope api.read \
--token-endpoint-auth-method client_secret_post --format json > client.json
CID=$(jq -r .client_id client.json); SEC=$(jq -r .client_secret client.json)
curl -s -X POST http://127.0.0.1:4444/oauth2/token \
-d grant_type=client_credentials -d client_id=$CID \
-d client_secret=$SEC -d scope=api.read
応答は {"access_token":"ory_at_…","expires_in":3599,"scope":"api.read","token_type":"bearer"} でした。上の例ではフォームでクライアントシークレットを送るため --token-endpoint-auth-method client_secret_post を付けています(付けないと client_secret_basic で登録され、invalid_client で拒否されます)。発行したトークンは hydra introspect token --endpoint http://127.0.0.1:4445 <token> で中身を確認でき、ACTIVE true と有効期限が表示されます。
Docker Composeのquickstartとサンプル画面の制約
Dockerで試す場合は、リポジトリ直下の quickstart.yml を使います。v26.2.0タグの定義は、oryd/hydra:v26.2.0 と、Node.js製のサンプルログイン・同意画面 oryd/hydra-login-consent-node:v26.2.0(3000番)、SQLiteのボリュームの組み合わせです。ファイル冒頭に「FOR DEMONSTRATION PURPOSES ONLY」とある通り、サンプル画面は [email protected]/foobar の固定の組だけを受け付け、subject も固定値を返す作りなので、そのまま本番には使えません。実装の参考にする場合は、固定認証を実際のユーザー認証に置き換え、画面側のCSRF対策なども確認します。
git clone https://github.com/ory/hydra.git && cd hydra && git checkout v26.2.0
docker compose -f quickstart.yml up
# PostgreSQLで試すときは quickstart-postgres.yml を重ねる
docker compose -f quickstart.yml -f quickstart-postgres.yml up
アクセストークンの形式:opaqueとJWTの選び方
既定のアクセストークンは ory_at_ で始まる不透明な文字列(opaque)で、APIサーバーはAdmin APIのイントロスペクションで有効性を確かめます。設定で strategies.access_token: jwt にすると、RS256で署名された約1,100文字のJWTに変わり、ペイロードは iss・sub・client_id・scp(スコープの配列)・exp などでした。
| 観点 | opaque(既定) | JWT |
|---|---|---|
| APIでの検証 | 毎回イントロスペクション | JWKSで署名検証 |
| 失効の即時反映 | される | expまで残る |
| トークン長(実測) | 94文字 | 約1,100文字 |
| 検証レイテンシ(公式掲載の目安) | 約50ms・通信条件に依存 | 約1ms・実装条件に依存 |
| 中身の露出 | なし | Base64で読める |
v26.2.0のソースでは、この設定の説明に「jwt is a bad idea」と書かれています。リンク先の公式ドキュメントは、失効させたJWTがexpまで有効に見えること、暗号化しない限り誰でも中身を読めること、pairwise subjectなど一部のOIDC機能が動かないことを挙げています。既定のopaqueのまま、イントロスペクションの結果をゲートウェイで短時間キャッシュする構成から始め(保持時間がそのまま失効の反映遅れになります)、イントロスペクションの負荷が問題になってからJWTを検討する順番を勧めます。JWTの検証手順はJWTの構造と署名検証の解説を参照してください。
対応データベースとjanitorによる本番運用
Hydra自身は状態を持たず、クライアント、ログイン・同意のセッション、トークン、署名鍵をすべてSQLデータベースに保存します。OryのDatabaseドキュメントはPostgreSQL・MySQL・CockroachDBを「fully supported」とし、SQLiteについては「must not be used in a production deployment」と明記しています。この記事の手順でSQLite版のバイナリを使っているのは手元の検証用だからで、本番はPostgreSQLかMySQLを選びます。v26.2.0の設定例(internal/config/config.yaml)ではPostgreSQLに「recommended」と付いています。DSNを memory にすると、再起動でデータがすべて消えます。
状態がDBにあるため、Hydraは複数台に並べて負荷分散できます。その代わり、期限切れのトークンやログイン・同意のリクエストがDBに溜まり続けます。hydra janitor がこれを一括削除するコマンドで、ヘルプに「This command is irreversible」とある通り元に戻せません。既定は --limit 10000・--batch-size 100 です。本番DBでは件数上限を付けて定期実行し、実行前にバックアップを取ってください。
Ory Network・OEL・セルフホストの選び方
Hydraの使い方は3通りあります。
| 形態 | 中身 | 費用 |
|---|---|---|
| セルフホスト(OSS) | Apache-2.0のHydraを自社で運用 | ライセンス費なし |
| Ory Network | Oryが運用するマネージド版 | 無料プランあり・有料は年$770〜 |
| Ory Enterprise License | OSSに無い機能付きのセルフホスト版 | 個別見積もり |
Ory Networkの料金ページ(2026年10月23日取得)では、Developerが無料、Productionが年$770、Growthが年$9,350、Enterpriseが個別見積もりです。有料プランは従量部分があり、月間クレジット(Production $21/Growth $255)を超えた分として、client_credentialsで発行するトークン(M2M Token)はProductionで1トークンあたり月$0.007、Growthで$0.006かかります。サービス間通信で大量にトークンを発行する設計なら、この単価で月額を見積もってからセルフホストと比べてください。
Ory Enterprise License(OEL)は、READMEによると、OSS版に無い追加機能、CVE修正を含む定期的なセキュリティリリースとSLA、プレミアムサポート、プライベートDockerレジストリが付くセルフホスト向けの契約です。OSSとして公開されるのは.0版だけで、途中のビルドはOEL契約者向けに配布されます。自社で運用しつつ、脆弱性修正の提供を契約で担保したい場合の選択肢です。
Keycloakとの違いと、Hydraを選ぶべきでない場面
| 観点 | Ory Hydra | Keycloak |
|---|---|---|
| ユーザー管理 | 持たない | 内蔵 |
| ログイン画面 | 自作(またはKratos) | 内蔵・テーマで変更 |
| LDAP/AD連携 | ログイン画面側で実装 | User Federationで設定 |
| 管理画面 | なし(CLI・API) | 管理コンソールあり |
| 実装言語 | Go | Java |
Hydraを選ぶ理由になるのは、既存の会員DBとログイン画面を動かさずにOAuth 2.0/OIDCを外付けしたい場合と、画面のUXを完全に自社で作りたい場合です。その代わり、この記事で見たログイン・同意・ログアウト・エラーの4画面と、skipやrejectの分岐は自社で実装し、保守し続けることになります。
次のどれかに当てはまるなら、Hydraは選ばないほうが早く終わります。
- 会員DBもログイン画面もまだ無く、パスワードリセットやMFAまで含めて一式が必要(Hydraだけでは何も揃わない。Kratosと組むか、KeycloakやIDaaSを使う)
- 運用担当が管理コンソールでクライアントやユーザーを操作したい(HydraはCLIとAPIのみ)
- LDAPやSAMLのIdPとの連携を設定だけで済ませたい
Keycloakの機能と導入判断はKeycloakのメリット・デメリットと比較で詳しく扱っています。既存の会員基盤にOAuth 2.0/OIDCを足す設計から相談したい場合は、認証基盤・ID管理システム開発でお受けしています。
よくある質問
Ory Hydraは無料で使えますか?
はい。ソースコードはApache-2.0ライセンスで公開されており、セルフホストならライセンス費用はかかりません(サーバーとDBの運用費は別途かかります)。マネージド版のOry Networkは有料プランがあります。
Ory Hydraだけでログイン画面まで作れますか?
作れません。Hydraはログイン・同意・ログアウトのリクエストをchallenge付きで外部の画面へ渡すだけです。画面は自作するか、Ory Kratosと組み合わせます。quickstartのサンプル画面は検証用です。
Ory Hydraの最新バージョンはいくつですか?
2026年10月時点の最新はv26.2.0(2026-03-20公開)です。v2.3.0の次がv25.4.0で、ここから年と四半期を表すカレンダー方式(YY.Q.B)の版番号になりました。最新はGitHubのリリース一覧で確認してください。
Ory HydraのAdmin APIに認証はかけられますか?
Hydra自体にはAdmin APIの認証機能がありません。4445番を社内ネットワークに閉じるか、APIゲートウェイで認証をかけるか、SERVE_ADMIN_HOST に unix: で始まるソケットの絶対パスを設定し、UNIXソケットのアクセス権で保護します。
Ory HydraとKratosの違いは何ですか?
Hydraはトークンを発行するOAuth 2.0/OIDCサーバー、Kratosはユーザー登録・ログイン・MFAを担う認証サーバーです。Kratosでログインした結果をHydraのログイン受理に渡す、という組み合わせで使います。Kratosの設定 oauth2_provider.url にHydraを指定すると、Kratosのログイン画面が login_challenge を直接処理します。