- OpenID Connect
- OAuth 2.1
- PKCE
- WebAuthn
- JWKS
- DPoP
- TOTP
Lobby
問いただすのではなく、迎え入れるサインインページ。
Lobbyは、Usher Identityがあなたのアプリのためにホストするサインインページです。行き先を必ず示し、どのアプリから来ても同じ見た目なので、ユーザーはLobbyを信頼できるようになります。
- 行き先の製品名を、毎回表示します。
- パスキー、メールで届くコード、マジックリンク。パスワードは必要な場合だけ。
- ライトでもダークでも、どの製品でも、同じ落ち着いたページ。
これは実際に動くLobbyの複製です。このページの中だけで動作し、何も送信せず、誰もサインインさせません。
囲い込みではなく、標準を
お使いのスタックが知っているプロトコルを、そのまま話します。
Usher Identityは、何よりもまずOpenID Connectプロバイダーです。都合に合わせてUsher IdentityのSDKを使うことも、どの言語のどのOIDCライブラリを使うこともできます。もしUsher Identityを離れることになっても、アプリのサインインの仕組みを変える必要はありません。
- OIDC Core · Discovery
OpenID Connect
環境ごとのディスカバリドキュメント、IDトークン、userinfo。認定済みのクライアントライブラリなら、どれでも使えます。
- S256のみ
OAuth 2.1とPKCE
パブリックでもコンフィデンシャルでも、すべてのクライアントでPKCE付きの認可コードフローを使います。インプリシットフローも、トークンエンドポイントでのパスワードもありません。
- RS256 · ES256 · EdDSA
JWKSと鍵のローテーション
各環境は専用の鍵で署名し、その鍵はjwks_uriで公開されます。サインイン中のユーザーに影響を与えずにローテーションできます。
- RFC 7662 · RFC 7009
イントロスペクションと失効
トークンがまだ有効かを確かめることも、今すぐ無効にすることもできます。Usher Identityはリクエストのたびに自身のセッションを確認するため、セッションの終了はすぐに反映されます。
RP-Initiated Logoutとバックチャネルログアウト
アプリからサインアウトすることも、どこかでセッションが終了したときに、Usher Identityからすべてのアプリへ知らせることもできます。
- RFC 9449
DPoP
トークンをクライアントが持つ鍵に結び付けるため、盗まれたトークンだけでは使えません。
- WebAuthn
パスキー
後付けではなく、最初から主役。指紋や顔、セキュリティキーでサインインでき、フィッシングで盗まれるものがありません。
- TOTP
認証アプリ
どの認証アプリの時間ベースのコードにも対応し、バックアップコードも使えます。2段階認証は任意にも必須にもできます。
マジックリンク
受信トレイからワンタップ。有効期間は短く、使えるのは一度きりで、送信元の環境に結び付けられています。
メールで届くコード
6桁の数字。サインインするデバイスと、メールを読むデバイスが違う人のために。
ソーシャルサインイン
Google、GitHub、Microsoft、Apple。アカウントが連携されるのは、メールアドレスが確認済みの場合だけです。
組織とチーム
アプリを利用する企業のための、メンバー、ロール、招待。
- 近日公開
SAML
顧客企業の従業員向けIDプロバイダーによるシングルサインオン。
- 近日公開
SCIM
顧客企業のディレクトリからのプロビジョニングとデプロビジョニング。
サインインの仕組み
5つのステップ。そのどれもが標準です。
これは、PKCEを使うOpenID Connectの認可コードフローです。本格的なIDプロバイダーなら、どこも同じフローを話します。スクロールしてご覧ください。
- 01
アプリがユーザーをLobbyへ送ります。
誰かが「Usher Identityで続ける」を選ぶと、アプリはそのユーザーを環境の認可エンドポイントへリダイレクトします。その際、PKCEチャレンジと、あとで確認するstate値を添えます。
GET acme.usherid.com/api/auth/oauth2/authorize ?response_type=code &client_id=acme_web &redirect_uri=https://app.acme.example/callback &scope=openid profile email offline_access &state=k3Jx… &code_challenge=E9Mel…cM &code_challenge_method=S256
- 02
ユーザーが、好きな方法でサインインします。
パスキー、メールで届くコード、マジックリンク、ソーシャルアカウント、パスワード。Lobbyは環境で許可された方法だけを提示し、どのアプリに進むのかを必ず表示します。
Usher IdentityUsher IdentityAcmeに進みますおかえりなさい。
パスキーを使用コードをメールで受け取る - 03
ユーザーが共有に同意します。
初回は、アプリが何を求めているか(プロフィール、メールアドレス、サインイン状態の維持)が表示され、一度同意すれば済みます。
Acmeが次の許可を求めています:
- 名前と写真の参照
- メールアドレスの参照
- サインイン状態の維持
キャンセル許可 - 04
Usher Identityがコードを返します。
ブラウザーは、5分間有効な一度きりのコードと、アプリが送ったstateを持って、リダイレクトURIに戻ります。アプリはそのstateを確認します。
302 Found Location: https://app.acme.example/callback ?code=SplxlOBeZQQYbYS6WxSbIA &state=k3Jx…
- 05
アプリがコードをトークンと交換します。
サーバーがコードとPKCEベリファイアをトークンエンドポイントに送ります。返ってくるのは、ユーザーが誰かを示すIDトークン、API用のアクセストークン、サインイン状態を保つためのリフレッシュトークンです。
POST acme.usherid.com/api/auth/oauth2/token grant_type=authorization_code&code=Splx… &code_verifier=dBjftJeZ4CVP… { "token_type": "Bearer", "access_token": "eyJhbGciOiJSUzI1NiIs…", "id_token": "eyJhbGciOiJSUzI1NiIs…", "refresh_token": "8xLOxBtZp8…", "expires_in": 600 }
設計による分離
どの環境も、それぞれが独立した建物です。
あなたの本番環境と開発環境、そしてほかのすべての顧客の環境は、重要なものを何ひとつ共有しません。ある環境でミスが起きても、別の環境のデータを読んだり、別の環境として署名したり、別の環境にサインインしたりすることはできません。
- 専用のPostgresスキーマ
- 共有テーブルのテナント列ではありません。その環境のためだけに作られ、ほかには何も入っていないスキーマです。
- 専用の署名鍵
- ある環境のトークンが、別の環境の鍵で検証を通ることはありません。
- 専用の鍵で封印されたシークレット
- その環境専用のデータキーで封印され、そのデータキー自体もマスターキーでラップされています。
- 専用のホスト
- 発行者はUsherのサイトやConsoleとは別のドメインにあり、ホスト限定のCookieを使います。
usheridentity.com
サイト、Usher Identity Console、Usher Identityアカウント
*.usherid.com
環境ごとに1つの発行者を、別のドメインに
ユーザー、セッション、トークンは、この環境のために作られたスキーマに保存されます。クエリはそのスキーマに対して実行され、テナント列を持つ共有テーブルが使われることはありません。
Acmeの本番環境にある封印済みのGoogleクライアントシークレットを、Northwindの本番環境にコピーする。
開発者向け
はじめてのサインインを、3つの方法で。
SDKが公開されたら組み込むもよし、使い慣れたOIDCライブラリを使うもよし、まずはディスカバリドキュメントを読むところから始めるもよし。どれも、根底にあるのは同じプロトコルです。
// app/layout.tsx
import { UsherProvider } from '@usher/nextjs'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<UsherProvider>{children}</UsherProvider>
</body>
</html>
)
}
// app/page.tsx
import { SignIn, UserButton, currentUser } from '@usher/nextjs'
export default async function Page() {
const user = await currentUser()
return user ? <UserButton /> : <SignIn />
}セルフホスト
あなたのサーバーで、あなたの鍵で。
Usher Identityをサービスとして使うことも、同じプラットフォームを自社のサーバーで、自社の鍵とデータベースを使って運用することもできます。
Docker
Composeファイルひとつで、アプリ、Postgres、Valkey、Caddyのエッジ、エグレスプロキシがそろいます。コンテナは新たな権限を得られない設定(no-new-privileges)で、ケーパビリティを削った状態で動作します。
Ubuntu
普通のUbuntuサーバーで十分です。TLSはCaddyが終端し、シークレットはコンテナに渡されるファイルで、イメージに焼き込まれることはありません。
Postgres
すべてのデータはPostgresに、環境ごとに1つのスキーマで保存されます。PostgresとValkeyは、インターネットへの経路がないネットワークに置かれます。
# on an Ubuntu server with Docker Engine and the Compose plugin
bash infra/scripts/setup-env.sh --prod \
--domain usher.example --tenant-domain usherid.example
docker compose -f compose.yaml -f compose.prod.yaml \
--profile core --profile apps --profile edge up -d --wait
pnpm db:migrate # applies the database migrationsセルフホストの詳しいガイドは準備中です。上のコマンドで、おおよその流れがわかります。
ユーザーを、中へご案内しましょう。
ワークスペースとプロジェクトを作成すれば、最初の環境に専用の発行者、鍵、Lobbyが用意されます。
サインインは一度だけ。どこへ行っても、ようこそ。