🔐 認証サービス
認証サービスは、アイデンティティの登録、ログイン、ログアウト、トークン管理を提供する完全な認証システムです。JWTベースのセキュリティおよびクッキー対応を備えています。
🚀 クイックスタート
Cookie 認証を使用する場合は、cookie-parser(および TypeScript 型定義)をインストールします。
npm install cookie-parser
npm install -D @types/cookie-parser
import express from 'express';
import cookieParser from 'cookie-parser';
import {services, middlewares, types, drivers} from '@nodeblocks/backend-sdk';
const {withMongo, createGoogleOAuthDriver, createTwitterOAuthDriver, createLineOAuthDriver} = drivers;
const connectToDatabase = withMongo('mongodb://localhost:27017/?authSource=admin', 'dev', 'user', 'password');
express()
// Cookie 認証を使用するルートより前に必要
.use(cookieParser())
.use(
services.authService(
{
...(await connectToDatabase('identities')),
...(await connectToDatabase('onetimetokens')),
...(await connectToDatabase('invitations')),
},
{
authSecrets: {
authEncSecret: 'your-encryption-secret',
authSignSecret: 'your-signing-secret',
},
maxFailedLoginAttempts: 5,
authMode: 'cookie',
accessTokenSignOptions: {expiresIn: '15m'},
refreshTokenSignOptions: {expiresIn: '2d'},
onetimeTokenSignOptions: {expiresIn: '5m'},
isMfaEnabled: false, // 多要素認証を有効にする
mfaCodeLength: 6, // MFA コードの長さ(既定値: 6)
mfaCodeEmailConfig: {
// isMfaEnabled が true の場合に必要
sender: 'noreply@example.com',
emailConfig: {
subject: 'Your MFA Code',
bodyTemplate: 'Your verification code is: ${code}',
},
},
verifyEmailConfig: {
enabled: true,
emailConfig: {
bodyTemplate: 'Hello ${email}',
subject: 'Welcome to our app',
urlTemplate: 'https://example.com/verify-email?token=${token}',
},
sender: 'noreply@example.com',
},
invitation: {
enabled: true,
emailConfig: {
bodyTemplate: '<h1>You\'re invited!</h1><p>Click <a href="${url}">here</a> to accept the invitation.</p>',
subject: "You're invited to join our organization",
urlTemplate: 'https://yourapp.com/invitations/accept?token=${token}&email=${email}',
sender: 'invites@yourapp.com',
},
target: 'invitation',
},
},
{
mailService: {
sendMail: async (mailData: types.MailData) => {
console.log(mailData);
return true;
},
},
googleOAuthDriver: createGoogleOAuthDriver(
process.env.GOOGLE_CLIENT_ID!,
process.env.GOOGLE_CLIENT_SECRET!,
'https://example.com/auth/oauth/google/callback',
),
twitterOAuthDriver: createTwitterOAuthDriver(
process.env.TWITTER_CONSUMER_KEY!,
process.env.TWITTER_CONSUMER_SECRET!,
'https://example.com/auth/oauth/twitter/callback',
process.env.SESSION_SECRET!,
),
lineOAuthDriver: createLineOAuthDriver(
process.env.LINE_CHANNEL_ID!,
process.env.LINE_CHANNEL_SECRET!,
'https://example.com/auth/oauth/line/callback',
),
}
)
)
.use(middlewares.nodeBlocksErrorMiddleware())
.listen(8089, () => console.log('Server running'));
🗄️ データストア
| コレクション | 必須 | 説明 |
|---|---|---|
identities | ✅ | 認証フローで使用するアイデンティティアカウント |
invitations | ❌ | 招待の作成・一覧・取得・削除で使用 |
onetimetokens | ❌ | MFA およびワンタイムトークンのフローで使用 |
📋 エンドポイント概要
| メソッド | パス | 説明 |
|---|---|---|
| 認証エンドポイント | ||
| POST | /auth/register | 新しいアイデンティティアカウントを登録 |
| POST | /auth/login | アイデンティティを認証しトークンを受け取る(MFA 有効時は MFA トークンを返す) |
| POST | /auth/mfa/verify | MFA コードを検証して認証を完了 |
| POST | /auth/mfa/resend | 検証用の MFA コードを再送 |
| POST | /auth/ott/login | ワンタイムトークン(マジックリンク)で認証 |
| POST | /auth/logout | ログアウトしトークンを無効化 |
| メール確認エンドポイント | ||
| POST | /auth/:identityId/send-verification-email | アイデンティティにメール確認を送信 |
| POST | /auth/confirm-email | 確認トークンでメールを確認 |
| メール管理エンドポイント | ||
| PATCH | /auth/:identityId/change-email | メール変更プロセスを開始 |
| POST | /auth/confirm-new-email | 新しいメールアドレスを確認 |
| パスワード管理エンドポイント | ||
| POST | /auth/send-reset-password-link-email | パスワード再設定メールを送信 |
| POST | /auth/reset-password | パスワード再設定を完了 |
| PATCH | /auth/:identityId/change-password | ユーザーパスワードを変更 |
| アカウント管理エンドポイント | ||
| POST | /auth/activate | ユーザーアカウントを有効化 |
| POST | /auth/deactivate | ユーザーアカウントを無効化 |
| トークン管理エンドポイント | ||
| POST | /auth/token/check | アクセストークンを検証 |
| POST | /auth/token/refresh | リフレッシュトークンでアクセストークンを更新 |
| DELETE | /auth/:identityId/refresh-tokens | アイデンティティのリフレッシュトークンを削除 |
| 招待エンドポイント | ||
| POST | /invitations | 招待を新規作成 |
| GET | /invitations | 招待を任意のフィルタで一覧取得 |
| GET | /invitations/:invitationId | IDで招待を取得 |
| DELETE | /invitations/:invitationId | 招待を削除 |
| OAuth エンドポイント | ||
| GET | /auth/oauth/google | Google OAuth フローを開始 |
| GET | /auth/oauth/google/callback | Google OAuth コールバックを処理 |
| GET | /auth/oauth/twitter | Twitter OAuth フローを開始 |
| GET | /auth/oauth/twitter/callback | Twitter OAuth コールバックを処理 |
| GET | /auth/oauth/line | LINE OAuth フローを開始 |
| GET | /auth/oauth/line/callback | LINE OAuth コールバックを処理 |
🗄️ エンティティスキーマ
認証サービスは以下のスキーマでアイデンティティを管理します:
アイデンティティエンティティ
{
"id": "string",
"email": "string",
"password": "string",
"attempts": "number",
"locked": "boolean",
"emailVerified": "boolean",
"deactivatedAt": "string | null",
"createdAt": "string",
"updatedAt": "string",
"typeId": "string",
"provider": "string",
"providerId": "string"
}
フィールド詳細
| フィールド | 型 | 自動生成 | 必須 | 説明 |
|---|---|---|---|---|
id | string | ✅ | ✅ | 一意な識別子(UUID) |
email | string | ❌ | ✅ | アイデンティティのメールアドレス |
password | string | ❌ | ✅ | ハッシュ化されたパスワード |
attempts | number | ✅ | ✅ | 失敗したログイン試行回数 |
locked | boolean | ✅ | ✅ | アカウントのロック状態 |
emailVerified | boolean | ✅ | ✅ | メールアドレスが確認済みかどうか |
deactivatedAt | string または null | ✅ | ❌ | アカウントの無効化日時。アクティブな場合は null |
createdAt | string | ✅ | ✅ | 作成日時 |
updatedAt | string | ✅ | ✅ | 更新日時 |
typeId | string | ❌ | ❌ | ロール識別子(例:管理者は "100"、一般は "001") |
provider | string | ❌ | ⚠️ | OAuth プロバイダーの識別子(例:google、twitter、line) |
providerId | string | ❌ | ⚠️ | OAuth アイデンティティ用のプロバイダー固有ユーザー ID |
補足フィールド詳細:
-
attempts: 連続した失敗ログイン回数を追跡します。しきい値(設定可能)を超えると自動でロックされます。
-
locked: 失敗回数の超過または管理操作によりロックされているかどうか。ロック中は認証できません。
-
typeId: システム内のロール/権限を示す識別子。サービスごとに調整可能。例:
- "100": 管理者(フルアクセス)
- "001": 一般ユーザー(基本権限)
- "000": ゲスト(最小権限)
- 必要に応じてカスタムロールを追加可能
-
email: OAuth ベースのアイデンティティでは、すべてのプロバイダーがメールアドレスを提供するわけではありません(たとえば Twitter)。通常の登録では必須です。
-
provider: このアイデンティティを作成した OAuth プロバイダーを示します。OAuth ベースのアイデンティティでは必須です。指定できる値は
'google'、'twitter'、'line'です。 -
providerId: OAuth プロバイダーがユーザーに割り当てる一意の識別子です。OAuth ベースのアイデンティティでは必須であり、
providerと組み合わせて複数回のログインにわたりアイデンティティを確実に識別します。
招待エンティティ
認証サービスは以下のスキーマで招待も管理します:
{
"id": "string",
"email": "string",
"fromIdentityId": "string",
"orgId": "string",
"role": "string",
"status": "string",
"createdAt": "string",
"updatedAt": "string"
}
招待フィールド詳細
| フィールド | 型 | 自動生成 | 必須 | 説明 |
|---|---|---|---|---|
id | string | ✅ | ✅ | 一意な識別子(UUID) |
email | string | ❌ | ✅ | 招待先のメールアドレス |
fromIdentityId | string | ❌ | ✅ | 招待送信者のアイデンティティID |
orgId | string | ❌ | ❌ | 招待先の組織ID |
role | string | ❌ | ❌ | 組織でのロール |
status | string | ❌ | ✅ | 招待の状態(例:pending / accepted) |
createdAt | string | ✅ | ✅ | 作成日時 |
updatedAt | string | ✅ | ✅ | 更新日時 |
🔐 認証ヘッダー
保護されたエンドポイントでは、以下のヘッダーを含めてください:
Authorization: Bearer <access_token>
x-nb-fingerprint: <device_fingerprint>
⚠️ 重要: 認可時にフィンガープリントを指定した場合、認証済みの全リクエストで
x-nb-fingerprintヘッダーが必須です。欠如している場合は 401 Unauthorized が返ります。
🔧 APIエンドポイント
1. アイデンティティ登録
メールアドレスとパスワードで新規アイデンティティを登録します。
リクエスト:
- Method:
POST - Path:
/auth/register - ヘッダー:
Content-Type: application/json
- 認可: 不要
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
email | string | ✅* | アイデンティティのメールアドレス |
password | string | ✅ | パスワード |
token | string | ✅* | 招待トークン |
*email または token のいずれかが必須(同時指定不可)。
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: 自動適用(email+password または token+password 必須)
- ルートバリデーション: なし
リクエスト例:
curl -X POST {{host}}/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securepassword123"
}'
トークン指定のリクエスト例(既存ユーザー):
curl -X POST {{host}}/auth/register \
-H "Content-Type: application/json" \
-d '{
"token": "invitation-token",
"password": "securepassword123"
}'
成功レスポンス:
HTTP/1.1 201 Created
Content-Type: application/json
エラーレスポンス:
メールが既に存在する場合:
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"error": {
"message": "unable to register \"user@example.com\""
}
}
必須フィールドが欠落している場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"request body must have required property 'email'",
"request body must have required property 'token'",
"request body must match exactly one schema in oneOf"
]
}
}
2. ログイン
資格情報を認証し、アクセストークンとリフレッシュトークンを受け取ります。
リクエスト:
- Method:
POST - Path:
/auth/login - ヘッダー:
Content-Type: application/json
- 認可: 不要
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
email | string | ✅ | メールアドレス |
password | string | ✅ | パスワード |
fingerprint | string | ❌ | 端末フィンガープリント |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
accessToken | string | API認証用のJWTアクセストークン |
id | string | アイデンティティID |
refreshToken | string | JWTリフレッシュトークン |
バリデーション:
- スキーマ検証: 自動適用(email, password 必須)
- ルートバリデーション: なし
リクエスト例:
curl -X POST {{host}}/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securepassword123",
"fingerprint": "device-fingerprint"
}'
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Credentials: true
Set-Cookie: accessToken=...; Path=/
Set-Cookie: refreshToken=...; Path=/
{
"accessToken": "c911c0dd107f8d7e92c0608aa149d041:dee2...",
"id": "0b3839a6-92b4-4044-a13b-ed834a105646",
"refreshToken": "9f0cad0da1ceec15c01de729a2359236:2acc8ee1b57fd971473..."
}
エラーレスポンス:
資格情報が不正な場合:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": {
"message": "wrong credentials provided"
}
}
3. MFA コードの検証
MFA が有効な場合に、ログインで受け取ったチャレンジトークンとメールで送信されたコードを検証して認証を完了します。
- Method:
POST - Path:
/auth/mfa/verify - 認可: 不要
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
token | string | ✅ | ログインで受け取った MFA チャレンジトークン |
code | string | ✅ | メールで送信された MFA 検証コード |
ベアラーモードでは accessToken、refreshToken、id を返します。Cookie モードではトークンを Cookie に設定し、本文には id のみを返します。コード、トークンが無効または期限切れの場合は 400 Bad Request を返します。
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
accessToken | string | API 認証用 JWT アクセストークン |
id | string | アイデンティティの一意識別子 |
refreshToken | string | 新しいアクセストークン取得用 JWT リフレッシュトークン |
curl -X POST {{host}}/auth/mfa/verify \
-H "Content-Type: application/json" \
-d '{"token":"mfa-challenge-token","code":"123456"}'
HTTP/1.1 200 OK
Content-Type: application/json
{"accessToken":"c911c0dd107f8d7e92c0608aa149d041:dee2...","id":"0b3839a6-92b4-4044-a13b-ed834a105646","refreshToken":"9f0cad0da1ceec15c01de729a2359236:2acc8ee1b57fd971473..."}
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Credentials: true
Set-Cookie: accessToken=...; Path=/; HttpOnly; Secure; SameSite=Strict
Set-Cookie: refreshToken=...; Path=/; HttpOnly; Secure; SameSite=Strict
{"id":"0b3839a6-92b4-4044-a13b-ed834a105646"}
{ "error": { "message": "Invalid MFA code" } }
{ "error": { "message": "Invalid or expired MFA token" } }
4. MFA コードの再送
MFA 検証コードをユーザーのメールアドレスへ再送します。
- Method:
POST - Path:
/auth/mfa/resend - 認可: 不要
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
token | string | ✅ | ログインで受け取った MFA チャレンジトークン |
成功時は、以前のトークンを無効にした新しい token を返します。トークンが無効・期限切れの場合は 400、アイデンティティが見つからない場合は 404 です。
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
token | string | 新しい MFA チャレンジトークン(以前のトークンは無効) |
curl -X POST {{host}}/auth/mfa/resend \
-H "Content-Type: application/json" \
-d '{"token":"mfa-challenge-token"}'
HTTP/1.1 200 OK
Content-Type: application/json
{"token":"new-mfa-challenge-token"}
{ "error": { "message": "Invalid or expired MFA token" } }
{ "error": { "message": "Identity not found" } }
5. ワンタイムトークンによるログイン
マジックリンクなどで発行されたワンタイムトークンによりユーザーを認証します。
- Method:
POST - Path:
/auth/ott/login - 認可: 不要
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
token | string | ✅ | 認証用ワンタイムトークン |
成功時のレスポンスは通常のログインと同じです。トークンがこの操作に使用できない場合は 403 Forbidden を返します。
レスポンスボディ(ベアラーモード):
| フィールド | 型 | 説明 |
|---|---|---|
accessToken | string | API 認証用 JWT アクセストークン |
id | string | アイデンティティの一意識別子 |
refreshToken | string | 新しいアクセストークン取得用 JWT リフレッシュトークン |
レスポンスボディ(Cookie モード):
| フィールド | 型 | 説明 |
|---|---|---|
id | string | アイデンティティの一意識別子 |
curl -X POST {{host}}/auth/ott/login \
-H "Content-Type: application/json" \
-d '{"token":"one-time-login-token"}'
{ "error": { "message": "Token is not valid for one-time login" } }
6. アクセストークンの更新
有効なリフレッシュトークンからアクセストークンを更新します。
- Method:
POST - Path:
/auth/token/refresh - ヘッダー: 必要に応じて
x-nb-fingerprint: <device-fingerprint> - 認可: 不要
ベアラーモードでは本文に refreshToken を指定し、新しい accessToken と refreshToken を受け取ります。Cookie モードでは refreshToken Cookie を使用し、更新後のトークンを Set-Cookie で返します。無効なリフレッシュトークンは 401 Unauthorized です。
リクエストボディ(ベアラーモード):
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
refreshToken | string | ✅ | 更新に使用する有効なリフレッシュトークン |
リクエストボディ(Cookie モード):
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| ボディなし | - | リフレッシュトークンは refreshToken Cookie から読み取る |
レスポンスボディ(ベアラーモード):
| フィールド | 型 | 説明 |
|---|---|---|
accessToken | string | 新しいアクセストークン |
refreshToken | string | 新しいリフレッシュトークン |
レスポンスボディ(Cookie モード):
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | トークンは Set-Cookie で設定され、本文は空 |
curl -X POST {{host}}/auth/token/refresh \
-H "Content-Type: application/json" \
-d '{"refreshToken":"<refresh-token>"}'
HTTP/1.1 200 OK
Content-Type: application/json
{"accessToken":"<access-token>","refreshToken":"<refresh-token>"}
{ "error": { "message": "Token is not valid refresh token" } }
7. リフレッシュトークンの削除
特定のアイデンティティのリフレッシュトークンを削除します。管理者または本人が実行できます。
- Method:
DELETE - Path:
/auth/:identityId/refresh-tokens - 認可: アクセストークン必須
成功時は 204 No Content を返します。対象のアイデンティティがない場合は 404 Not Found です。
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時は 204 No Content を返す |
curl -X DELETE {{host}}/auth/<identityId>/refresh-tokens \
-H "Authorization: Bearer <access-token>"
HTTP/1.1 204 No Content
{ "error": { "message": "Identity not found" } }
8. ログアウト
ログアウトし、リフレッシュトークンを無効化します。
リクエスト:
- Method:
POST - Path:
/auth/logout - ヘッダー:
Authorization: Bearer <token>x-nb-fingerprint: <device-fingerprint>
- 認可: ベアラートークン必須
リクエストボディ(ベアラーモード):
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
refreshToken | string | ✅ | 失効させるリフレッシュトークン |
リクエストボディ(Cookie モード):
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| ボディなし | - | リフレッシュトークンは refreshToken Cookie から読み取る |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: ベアラーモードでは JSON 本文の
refreshTokenが必須です。Cookie モードでは空の本文スキーマを使用します。 - ルートバリデーション: 認証済みリクエスト(ベアラートークン)必須
リクエスト例:
curl -X POST {{host}}/auth/logout \
-H "Authorization: Bearer <access-token>" \
-H "Content-Type: application/json" \
-d '{"refreshToken":"<refresh-token>"}'
Cookie モードのリクエスト例:
curl -X POST {{host}}/auth/logout \
-H "Cookie: accessToken=<access-token>; refreshToken=<refresh-token>"
成功レスポンス:
HTTP/1.1 204 No Content
エラーレスポンス:
リフレッシュトークンの無効化に失敗した場合:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "failed to delete refresh token"
}
}
9. 確認メール送信
アイデンティティのメールアドレス宛に確認用リンクを送信します。
リクエスト:
- Method:
POST - Path:
/auth/:identityId/send-verification-email - ヘッダー:
Authorization: Bearer <token>x-nb-fingerprint: <device-fingerprint>
- 認可: ベアラートークン必須(管理者または本人)
パスパラメータ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
identityId | string | ✅ | アイデンティティの一意なID |
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
fingerprint | string | ❌ | セキュリティ用の端末フィンガープリント |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: 自動適用
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者または本人であること
リクエスト例:
curl -X POST {{host}}/auth/identity-12345/send-verification-email \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"fingerprint": "device-fingerprint"
}'
成功レスポンス:
HTTP/1.1 204 No Content
Content-Type: application/json
エラーレスポンス:
メール確認機能が無効な場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "verification email feature not enabled"
}
}
メールサービスが未設定の場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "verification email feature requires a mail service to be provided"
}
}
メール設定が不足している場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "verifyEmailConfig requires emailConfig with fields bodyTemplate, subject, urlTemplate"
}
}
メール送信に失敗した場合:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "Failed to send verification email"
}
}
アイデンティティが見つからない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{ "error": { "message": "Identity not found" } }
アイデンティティにメールアドレスがない場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{ "error": { "message": "Identity has no email address" } }
ワンタイムトークンの生成に失敗した場合:
HTTP/1.1 501 Not Implemented
Content-Type: application/json
{ "error": { "message": "failed to generate onetime token" } }
10. メール確認
確認トークンを使用してメールアドレスを確認します。
リクエスト:
- Method:
POST - Path:
/auth/confirm-email - ヘッダー:
Content-Type: application/json
- 認可: 不要
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
token | string | ✅ | メールに記載の確認トークン |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: 自動適用(token 必須)
- ルートバリデーション: なし
リクエスト例:
curl -X POST {{host}}/auth/confirm-email \
-H "Content-Type: application/json" \
-d '{
"token": "jwt-verification-token"
}'
成功レスポンス:
HTTP/1.1 204 No Content
Content-Type: application/json
エラーレスポンス:
トークンが無効な場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Unable to verify token"
}
}
11. 招待の作成
サービスへの参加招待を新規作成します。
リクエスト:
- Method:
POST - Path:
/invitations - ヘッダー:
Content-Type: application/jsonAuthorization: Bearer <token>x-nb-fingerprint: <device-fingerprint>
- 認可: ベアラートークン必須(管理者)
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
email | string | ✅ | 招待先のメールアドレス |
fromIdentityId | string | ✅ | 招待送信者のアイデンティティID |
orgId | string | ❌ | 招待先の組織ID |
role | string | ❌ | 組織内ロール |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
invitationId | string | 作成された招待の一意ID |
バリデーション:
- スキーマ検証: 自動適用(email, fromIdentityId 必須・追加プロパティ不可)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者権限必須
リクエスト例:
curl -X POST {{host}}/invitations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"email": "newuser@example.com",
"fromIdentityId": "392157b1-dc7a-4935-a6f9-a2d333b910ea"
"orgId": "org123",
"role": "member"
}'
成功レスポンス:
HTTP/1.1 201 Created
Content-Type: application/json
{
"invitationId": "62564a60-e720-4907-bb85-3afaa2729e0d"
}
エラーレスポンス:
必須フィールドが欠落している場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"request body must have required property 'email'"
]
}
}
fromIdentityId が欠落している場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"request body must have required property 'fromIdentityId'"
]
}
}
email の形式が不正な場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"request body must match format \"email\""
]
}
}
追加プロパティが含まれる場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"request body must NOT have additional properties"
]
}
}
招待の作成に失敗した場合:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "Failed to create invitation"
}
}
12. 招待一覧
招待をフィルター・ページング付きで取得します。
リクエスト:
- Method:
GET - Path:
/invitations - ヘッダー:
Authorization: Bearer <token>x-nb-fingerprint: <device-fingerprint>
- 認可: ベアラートークン必須(管理者)
クエリパラメータ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
email | string | ❌ | 招待先メールでフィルター |
fromIdentityId | string | ❌ | 招待送信者IDでフィルター |
orgId | string | ❌ | 組織IDでフィルター |
role | string | ❌ | ロールでフィルター |
page | number | ❌ | ページ番号 |
limit | number | ❌ | 1ページ件数 |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
email | string | 招待先のメールアドレス |
fromIdentityId | string | 招待送信者のアイデンティティID |
orgId | string | 組織ID |
role | string | 組織内ロール |
status | string | 招待の状態(例: pending/accepted) |
createdAt | string | 作成日時 |
id | string | 招待の一意ID |
updatedAt | string | 更新日時 |
バリデーション:
- スキーマ検証: 自動適用
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者権限必須
リクエスト例:
curl -X GET "{{host}}/invitations" \
-H "Authorization: Bearer <access-token>"
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"email": "newuser@example.com",
"fromIdentityId": "392157b1-dc7a-4935-a6f9-a2d333b910ea",
"orgId": "org123",
"role": "member",
"status": "pending",
"createdAt": "2025-07-04T06:29:32.905Z",
"id": "62564a60-e720-4907-bb85-3afaa2729e0d",
"updatedAt": "2025-07-04T06:29:32.905Z"
}
]
空レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
[]
13. 招待の取得(ID指定)
一意IDで特定の招待を取得します。
リクエスト:
- Method:
GET - Path:
/invitations/:invitationId - ヘッダー:
Authorization: Bearer <token>x-nb-fingerprint: <device-fingerprint>
- 認可: ベアラートークン必須(管理者)
パスパラメータ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
invitationId | string | ✅ | 招待の一意ID |
バリデーション:
- スキーマ検証: 自動適用
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者権限必須
リクエスト例:
curl -X GET {{host}}/invitations/62564a60-e720-4907-bb85-3afaa2729e0d \
-H "Authorization: Bearer <access-token>"
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
{
"email": "newuser@example.com",
"fromIdentityId": "392157b1-dc7a-4935-a6f9-a2d333b910ea",
"orgId": "org123",
"role": "member",
"status": "pending",
"createdAt": "2025-07-04T06:29:32.905Z",
"id": "62564a60-e720-4907-bb85-3afaa2729e0d",
"updatedAt": "2025-07-04T06:29:32.905Z"
}
エラーレスポンス:
招待が見つからない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Invitation not found"
}
}
14. 招待の削除
一意IDで特定の招待を削除します。
リクエスト:
- Method:
DELETE - Path:
/invitations/:invitationId - ヘッダー:
Authorization: Bearer <token>x-nb-fingerprint: <device-fingerprint>
- 認可: ベアラートークン必須(管理者)
パスパラメータ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
invitationId | string | ✅ | 招待の一意ID |
バリデーション:
- スキーマ検証: 自動適用
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者権限必須
リクエスト例:
curl -X DELETE {{host}}/invitations/62564a60-e720-4907-bb85-3afaa2729e0d \
-H "Authorization: Bearer <access-token>"
成功レスポンス:
HTTP/1.1 204 OK
Content-Type: application/json
エラーレスポンス:
招待が見つからない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Invitation not found"
}
}
15. メール変更の開始
新しいメールアドレスに確認メールを送信し、メール変更プロセスを開始します。
リクエスト:
- Method:
PATCH - Path:
/auth/:identityId/change-email - ヘッダー:
Content-Type: application/json
- 認可: ベアラートークン必須(管理者または本人)
パスパラメータ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
identityId | string | ✅ | アイデンティティの一意ID |
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
email | string | ✅ | 新しいメールアドレス |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: 自動適用(email 必須・メール形式)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者または本人であること
リクエスト例:
curl -X PATCH {{host}}/auth/identity-12345/change-email \
-H "Content-Type: application/json" \
-d '{
"email": "newemail@example.com"
}'
成功レスポンス:
HTTP/1.1 204 No Content
Content-Type: application/json
エラーレスポンス:
メールが既に存在する場合:
HTTP/1.1 409 Conflict
Content-Type: application/json
{
"error": {
"message": "Email already exists"
}
}
アイデンティティが見つからない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Identity not found"
}
}
16. 新しいメールの確認
ワンタイム確認トークンで新しいメールアドレスを確定します。
リクエスト:
- Method:
POST - Path:
/auth/confirm-new-email - ヘッダー:
Content-Type: application/json
- 認可: 不要
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
token | string | ✅ | メールの確認トークン |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: 自動適用(token 必須)
- ルートバリデーション: なし
リクエスト例:
curl -X POST {{host}}/auth/confirm-new-email \
-H "Content-Type: application/json" \
-d '{
"token": "jwt-verification-token"
}'
成功レスポンス:
HTTP/1.1 204 No Content
Content-Type: application/json
エラーレスポンス:
トークンが無効な場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Invalid token"
}
}
17. パスワード再設定リンク送信
メールアドレスに基づいてパスワード再設定リンクを送信します。
リクエスト:
- Method:
POST - Path:
/auth/send-reset-password-link-email - ヘッダー:
Content-Type: application/json
- 認可: 不要
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
email | string | ✅ | パスワード再設定用のメールアドレス |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: 自動適用(email 必須・メール形式)
- ルートバリデーション: なし
リクエスト例:
curl -X POST {{host}}/auth/send-reset-password-link-email \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com"
}'
成功レスポンス:
HTTP/1.1 204 No Content
Content-Type: application/json
エラーレスポンス:
メールが見つからない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Email not found"
}
}
18. パスワード再設定の完了
トークンを検証し、新しいパスワードに更新して再設定を完了します。
リクエスト:
- Method:
POST - Path:
/auth/reset-password - ヘッダー:
Content-Type: application/jsonAuthorization: Bearer <one-time-token>
- 認可: ベアラートークン必須(ワンタイムトークン)
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
password | string | ✅ | 新しいパスワード(8〜24文字、英小文字と数字を含む) |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: 自動適用(password 必須・セキュリティ要件を満たす)
- ルートバリデーション: なし
リクエスト例:
curl -X POST {{host}}/auth/reset-password \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <one-time-token>" \
-d '{
"password": "newSecurePassword123"
}'
成功レスポンス:
HTTP/1.1 204 No Content
Content-Type: application/json
エラーレスポンス:
トークンが無効な場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Invalid token"
}
}
パスワードが要件を満たさない場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"password must match pattern \"^(?=.*[a-z])(?=.*\\d)[a-zA-Z0-9?/_-]{8,24}$\""
]
}
}
19. パスワード変更
PATCH /auth/:identityId/change-password でパスワードを変更します。
リクエスト:
- Method:
PATCH - Path:
/auth/:identityId/change-password - ヘッダー:
Content-Type: application/jsonAuthorization: Bearer <token>x-nb-fingerprint: <device-fingerprint>
- 認可: ベアラートークン必須
パスパラメータ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
identityId | string | ✅ | アイデンティティの一意ID |
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
password | string | ✅ | 現在のパスワード(確認用) |
newPassword | string | ✅ | 新しいパスワード(8〜24文字、英小文字と数字を含む) |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: 自動適用(password, newPassword 必須・要件を満たす)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者または本人であること
リクエスト例:
curl -X PATCH {{host}}/auth/identity-12345/change-password \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"password": "oldPassword123",
"newPassword": "newSecurePassword123"
}'
成功レスポンス:
HTTP/1.1 204 No Content
Content-Type: application/json
エラーレスポンス:
現在のパスワードが正しくない場合:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": {
"message": "Current password is incorrect"
}
}
新しいパスワードが要件を満たさない場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"newPassword must match pattern \"^(?=.*[a-z])(?=.*\\d)[a-zA-Z0-9?/_-]{8,24}$\""
]
}
}
20. アカウント有効化
POST /auth/activate でアカウントを有効化します。
リクエスト:
- Method:
POST - Path:
/auth/activate - ヘッダー:
Content-Type: application/jsonAuthorization: Bearer <token>
- 認可: ベアラートークン必須(管理者)
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
identityId | string | ✅ | 有効化対象のアイデンティティID |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: 自動適用(identityId 必須)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者権限必須
リクエスト例:
curl -X POST {{host}}/auth/activate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"identityId": "identity-12345"
}'
成功レスポンス:
HTTP/1.1 204 No Content
Content-Type: application/json
エラーレスポンス:
アイデンティティが見つからない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Identity not found"
}
}
メールが未確認の場合:
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"error": {
"message": "Email must be verified before activation"
}
}
21. アカウント無効化
POST /auth/deactivate でアイデンティティを無効化します。
リクエスト:
- Method:
POST - Path:
/auth/deactivate - ヘッダー:
Content-Type: application/jsonAuthorization: Bearer <token>
- 認可: ベアラートークン必須(管理者または本人)
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
identityId | string | ✅ | 無効化対象のアイデンティティID |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: 自動適用(identityId 必須)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者または本人であること
リクエスト例:
curl -X POST {{host}}/auth/deactivate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"identityId": "identity-12345"
}'
成功レスポンス:
HTTP/1.1 204 No Content
Content-Type: application/json
エラーレスポンス:
アイデンティティが見つからない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Identity not found"
}
}
メールが未確認の場合:
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"error": {
"message": "Email must be verified before deactivation"
}
}
トークンが欠落している場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Missing token header"
}
}
メール送信に失敗した場合:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "Failed to send email"
}
}
22. トークン検証
アクセストークンを検証し、その状態を返します。
リクエスト:
- Method:
POST - Path:
/auth/token/check - ヘッダー:
Content-Type: application/json
- 認可: 不要
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
token | string | ✅ | 検証対象のトークン |
target | string | ❌ | 任意の検証コンテキスト |
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
identityId | string | 有効な場合のアイデンティティID |
バリデーション:
- スキーマ検証: 自動適用(token 必須)
- ルートバリデーション: なし
リクエスト例:
curl -X POST {{host}}/auth/token/check \
-H "Content-Type: application/json" \
-d '{
"token": "jwt-token-to-validate",
"target": "optional-target-context"
}'
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
{
"identityId": "811ff0a3-a26f-447b-b68a-dd83ea4000b9"
}
エラーレスポンス:
トークンが無効な場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Unable to verify token"
}
}
23. Google OAuth 開始
Google の認可ページにリダイレクトして OAuth 認証フローを開始します。ログイン/サインアップの両方に利用でき、未登録ユーザーは自動作成、既存ユーザーは認証されます。
リクエスト:
- Method:
GET - Path:
/auth/oauth/google - ヘッダー: なし
- 認可: 不要
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| ボディなし | - | なし。設定はクエリパラメータで指定 |
クエリパラメータ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
fp | string | ✅ | 端末フィンガープリント |
purpose | string | ✅ | フロー目的:oauth-login または oauth-signup |
redirectUrl | string | ✅ | 完了後のリダイレクトURL |
typeId | string | ❌ | アイデンティティ種別ID(サインアップ時に必要) |
レスポンス:
- ステータス:
302 Found - ヘッダー: Google OAuth URL を含む
Location
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時はレスポンスボディなし |
リクエスト例:
# OAuth Login
curl -v "{{host}}/auth/oauth/google?fp=device-fingerprint&purpose=oauth-login&redirectUrl=http://localhost/oauth/callback"
# OAuth Signup
curl -v "{{host}}/auth/oauth/google?fp=device-fingerprint&purpose=oauth-signup&redirectUrl=http://localhost/oauth/callback&typeId=001"
成功レスポンス:
HTTP/1.1 302 Found
Location: https://accounts.google.com/o/oauth2/v2/auth?prompt=consent&response_type=code&redirect_uri=...&scope=email%20profile&state=...&client_id=...
エラーレスポンス:
必須パラメータが不足している場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"query parameter 'fp' is required",
"query parameter 'purpose' is required",
"query parameter 'redirectUrl' is required"
]
}
}
purpose が不正な値の場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"query parameter 'purpose' must be equal to one of the allowed values"
]
}
}
24. Google OAuth コールバック
Google OAuth のコールバックを処理し、認証フローを完了します。成功後は初回の OAuth リクエストで指定された redirectUrl にリダイレクトされ、認証トークン(ワンタイムまたはアクセストークン)が付与されます。
リクエスト:
- Method:
GET - Path:
/auth/oauth/google/callback - ヘッダー: なし
- 認可: 不要
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| ボディなし | - | なし。処理はクエリパラメータで行う |
クエリパラメータ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
code | string | ✅ | Google からのワンタイム認可コード(Passport.js により交換) |
state | string | ✅ | フロー文脈を含む署名付きJWT(purpose, redirectUrl, typeId, fingerprint, userAgent) |
レスポンス:
- ステータス:
302 Found(最終遷移先へリダイレクト) - ヘッダー: 最終リダイレクトURLの
Location
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| ボディなし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: なし
- ルートバリデーション: なし
リクエスト例:
curl -v "{{host}}/auth/oauth/google/callback?code=AUTH_CODE&state=STATE_TOKEN"
成功レスポンス:
HTTP/1.1 302 Found
Location: http://localhost:3000/oauth/callback?token=JWT_TOKEN
エラーレスポンス:
OAuth state が無効または期限切れの場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Invalid onetime token"
}
}
サインアップに typeId が必要な場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "typeId is required"
}
}
アイデンティティ作成に失敗した場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Failed to create identity"
}
}
該当するアイデンティティが見つからない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "No identity found for the given email."
}
}
DB操作に失敗した場合:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"message": "Error finding or creating identity"
}
}
25. Twitter OAuth 開始
Twitter OAuth を開始するには GET /auth/oauth/twitter を使用します。purpose と redirectUrl を指定し、サインアップ時には typeId を追加します。Twitter の開始フローには fp は不要です。
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| リクエストボディなし | - | - | ボディは不要です。設定にはクエリパラメータを使用します。 |
| クエリパラメータ | 型 | 必須 | 説明 |
|---|---|---|---|
purpose | string | ✅ | OAuth の目的: oauth-login または oauth-signup |
redirectUrl | string | ✅ | OAuth 完了後のリダイレクト先 URL |
typeId | string | ❌ | アイデンティティ種別 ID(サインアップ時は必須) |
成功時は 302 Found と Twitter OAuth URL を含む Location ヘッダーを返し、本文はありません。
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| レスポンスボディなし | - | OAuth 開始エンドポイントは成功時にレスポンスボディを返しません。 |
# OAuth Login
curl -v "{{host}}/auth/oauth/twitter?purpose=oauth-login&redirectUrl=http://localhost/oauth/callback"
# OAuth Signup
curl -v "{{host}}/auth/oauth/twitter?purpose=oauth-signup&redirectUrl=http://localhost/oauth/callback&typeId=001"
HTTP/1.1 302 Found
Location: https://api.twitter.com/oauth/authenticate?oauth_token=...
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": ["query parameter 'purpose' is required", "query parameter 'redirectUrl' is required"]
}
}
purpose=oauth-login を指定すると、既存アイデンティティ用の Twitter ログインフローを開始します。purpose=oauth-signup と typeId を指定すると、新規アイデンティティ用のサインアップフローを開始します。
26. Twitter OAuth コールバック
GET /auth/oauth/twitter/callback は認可後に Twitter から自動的に呼び出されます。サービスは認証結果を指定された redirectUrl へリダイレクトします。
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| リクエストボディなし | - | - | ボディは不要です。OAuth コールバック処理にはクエリパラメータを使用します。 |
| クエリパラメータ | 型 | 必須 | 説明 |
|---|---|---|---|
oauth_token | string | ✅ | Twitter の OAuth トークン |
oauth_verifier | string | ✅ | Twitter の OAuth 検証子 |
レスポンス: 302 Found(最終的な宛先へリダイレクト)と、最終リダイレクト URL を含む Location ヘッダーを返します。
レスポンスボディ:
| フィールド | 型 | 説明 |
|---|---|---|
| レスポンスボディなし | - | OAuth コールバックエンドポイントは成功時にレスポンスボディを返しません。 |
バリデーション: スキーマ検証およびルートバリデーターはありません。
curl -v "{{host}}/auth/oauth/twitter/callback?oauth_token=OAUTH_TOKEN&oauth_verifier=OAUTH_VERIFIER"
HTTP/1.1 302 Found
Location: http://localhost:3000/oauth/callback?token=JWT_TOKEN
{ "error": { "message": "Invalid OAuth token" } }
サインアップで種別 ID がない場合は "typeId is required"、アイデンティティの作成に失敗した場合は "Failed to create identity" が返されます。
{ "error": { "message": "No identity found for the given twitter account." } }
27. LINE OAuth 開始
LINE OAuth を開始するには GET /auth/oauth/line を使用します。fp、purpose、redirectUrl を指定し、サインアップ時には typeId を追加します。
| クエリパラメータ | 型 | 必須 | 説明 |
|---|---|---|---|
fp | string | ✅ | セキュリティ用デバイスフィンガープリント |
purpose | string | ✅ | OAuth の目的: oauth-login または oauth-signup |
redirectUrl | string | ✅ | 認証後のリダイレクト先 URL |
typeId | string | ❌ | 新規アイデンティティの種別 ID(サインアップ時は必須) |
認可は不要です。成功時は LINE の認可ページへ移動する 302 Found と Location ヘッダーを返し、本文はありません。
curl -X GET "{{host}}/auth/oauth/line?fp=device-fingerprint&purpose=oauth-signup&redirectUrl=https://example.com/auth/callback&typeId=regular"
HTTP/1.1 302 Found
Location: https://access.line.me/oauth2/v2.1/authorize?...
{ "error": { "message": "redirectUrl is required" } }
{ "error": { "message": "typeId is required" } }
28. LINE OAuth コールバック
GET /auth/oauth/line/callback は LINE の認可後に呼び出されます。設定不足、無効な state、またはプロバイダーエラーは適切な 400 または 500 のエラーレスポンスになります。
| クエリパラメータ | 型 | 必須 | 説明 |
|---|---|---|---|
code | string | ✅ | LINE からの認可コード |
state | string | ✅ | CSRF 保護用の state パラメータ |
成功時は最終的なリダイレクト先を含む Location ヘッダー付きの 302 Found を返します。スキーマ検証とルートバリデーターはありません。
# LINE が認可後に自動的に呼び出します
GET {{host}}/auth/oauth/line/callback?code=AUTHORIZATION_CODE&state=STATE_STRING
HTTP/1.1 302 Found
Location: https://example.com/auth/callback?token=ACCESS_TOKEN
{ "error": { "message": "LINE authorization failed" } }
OAuth フローの補足:
purpose=oauth-loginは、既存の外部プロバイダーアカウントでログインするフローです。purpose=oauth-signupは、新しいアイデンティティを作成するフローです。- サインアップでは
typeIdを指定してください。指定しない場合、プロバイダーのコールバックを完了できません。 redirectUrlは OAuth 処理の完了後にユーザーエージェントを戻す URL です。fpは Google と LINE の開始リクエストで使用するデバイスフィンガープリントです。- Twitter の開始リクエストでは
fpを指定しません。 - Google、Twitter、LINE の開始エンドポイントは、各プロバイダーの認可 URL へ
302 Foundでリダイレクトします。 - コールバックエンドポイントは、プロバイダーから返された認可コードまたは OAuth トークンを処理します。
- Google のコールバックでは、プロバイダーが発行した
codeと署名付きのstateを使用します。 - Twitter のコールバックでは、
oauth_tokenとoauth_verifierを使用します。 - LINE のコールバックでは、認可コード
codeと CSRF 保護用のstateを使用します。 - コールバックが成功すると、初期リクエストで指定した
redirectUrlへ認証情報付きでリダイレクトされます。 - OAuth プロバイダーで既存のアイデンティティが見つからない場合、サービスは対応する
404エラーを返します。 - 無効または期限切れの認可情報は
400エラーになります。 - OAuth 設定やプロバイダー通信に失敗した場合は
500エラーになります。 - OAuth の開始とコールバックは、リクエストボディを必要としません。
- クエリパラメータは URL エンコードして渡してください。
- コールバック URL は、各 OAuth プロバイダーのアプリケーション設定に登録する必要があります。
- 本番環境では
redirectUrlを信頼済みの宛先に制限してください。 - 認証トークンやプロバイダーの認可コードをログへ出力しないでください。
- OAuth の開始前に、各プロバイダーのクライアント ID、クライアントシークレット、コールバック URL を設定してください。
- リダイレクト先では、アプリケーションが受け取った認証結果を安全に処理してください。
- 同じユーザーが初めてログインする場合のアイデンティティ作成は、サービスの設定および
purposeに従って行われます。 - 既存アカウントとの関連付けは、プロバイダー固有のユーザー ID を使用して判定されます。
- ユーザーがプロバイダー側で認可を拒否した場合、アプリケーションは失敗したリダイレクトを処理できるようにしてください。
stateはリクエストに紐づくコンテキストを保持し、コールバック処理時の検証に使用されます。- 認可フロー中にブラウザーを閉じた場合、ユーザーは開始エンドポイントから再度フローを実行できます。
- 外部プロバイダーの設定値は環境変数などの安全な設定機構で管理してください。
- OAuth 連携を変更した後は、ログインとサインアップの両方のリダイレクトフローをテストしてください。
- エラー時のリダイレクト先にも、ユーザーが安全に再試行できる画面を用意してください。
- Google OAuth では、Google が発行した認可コードをトークン交換に使用します。
- Twitter OAuth では、OAuth トークンと検証子の組み合わせを使用します。
- LINE OAuth では、LINE の認可コードをトークン交換に使用します。
Locationヘッダーはブラウザーに次の遷移先を通知します。- OAuth のリダイレクト応答は API JSON 応答とは異なり、通常はブラウザーで処理されます。
- API クライアントで検証する場合は、リダイレクトを追跡する HTTP クライアントを使用してください。
- 認可コードは短時間で失効するため、受け取ったら速やかにコールバック処理を完了してください。
- 失敗した OAuth フローを再利用するのではなく、新しい開始リクエストを発行してください。
{ "error": { "message": "Identity creation failed" } }
{ "error": { "message": "No identity found for the given LINE account." } }
コールバックエンドポイントは直接のクライアント呼び出しではなく、LINE の認可処理からのリダイレクト先です。
🔒 セキュリティ機能
アカウント保護
- ログイン失敗回数の追跡: 失敗回数を記録
- アカウントロック: 規定回数(既定は5回、変更可)で自動ロック
- パスワードハッシュ化: パスワードは安全にハッシュ化
- トークンセキュリティ: デバイス指紋とIP検証を含む
トークン管理
- アクセストークン: 短寿命のAPIアクセス用トークン
- リフレッシュトークン: 再発行用の長寿命トークン
- トークン検証: ドメイン・指紋・IP・UA を検証
- セキュアクッキー: HTTP-only/secure で安全に保存
認証方法
ベアラートークン
// Use in Authorization header
Authorization: Bearer <access-token>
クッキー認証
// Tokens automatically sent with requests
⚙️ 設定オプション
サービス設定
interface AuthServiceConfig {
authSecrets?: {
authEncSecret: string; // JWT encryption secret
authSignSecret: string; // JWT signing secret
};
maxFailedLoginAttempts?: number; // Default: 5
authMode?: 'bearer' | 'cookie';
checkIp?: boolean;
cookieOpts?: {
domain?: string;
maxAge?: string | number;
path?: string;
sameSite?: 'strict' | 'lax' | 'none';
};
jwtOpts?: {
jwtSignOptions?: SignOptions;
stateful?: boolean;
};
accessTokenSignOptions?: SignOptions; // Default: {expiresIn: '15m'}
onetimeTokenSignOptions?: SignOptions; // Default: {expiresIn: '5m'}
refreshTokenSignOptions?: SignOptions; // Default: {expiresIn: '2d'}
isMfaEnabled?: boolean;
mfaCodeLength?: number;
mfaCodeEmailConfig?: {
sender: string;
emailConfig: {subject: string; bodyTemplate: string};
};
identity?: {
typeIds?: {
admin: string; // Admin user type identifier
guest: string; // Guest user type identifier
regular: string; // Regular user type identifier
};
};
verifyEmailConfig?: {
enabled: boolean; // Enable email verification feature
emailConfig?: {
bodyTemplate: string; // Email body template with {{email}} and {{token}} placeholders
subject: string; // Email subject line
urlTemplate: string; // URL template with {{token}} placeholder
};
sender?: string; // Sender email address
};
invitation?: {
enabled: boolean; // Enable invitation feature
emailConfig?: {
bodyTemplate: string; // Email body template with {{email}} and {{token}} placeholders
subject: string; // Email subject line
urlTemplate: string; // URL template with {{token}} placeholder
sender: string; // Sender email address
};
target?: string; // Token target for invitation validation
};
}
設定詳細
認証サービスの設定は、セキュリティ・クッキー・JWT・招待・メール確認の論理グループに整理されています。
🔐 セキュリティ設定
authSecrets - JWT トークンのセキュリティ用シークレット
- 型:
{ authEncSecret: string; authSignSecret: string } - 説明: JWT の暗号化・署名に用いるシークレットキー
- 既定:
{ authEncSecret: '', authSignSecret: '' } - 必須: 本番環境では必須
- 子プロパティ:
authEncSecret: JWT ペイロード暗号化用のシークレットauthSignSecret: JWT 署名検証用のシークレット
maxFailedLoginAttempts - アカウントロックのしきい値
- 型:
number - 説明: ロックされるまでに許容されるログイン失敗回数の上限
- 既定:
5 - 挙動: しきい値超過でアカウントをロック(解除は手動)
🔐 多要素認証(MFA)設定
isMfaEnabled はログイン時の多要素認証を有効にします。型は boolean、既定値は false です。有効時は資格情報の検証後にメールで送信したコードの検証を要求するため、mfaCodeEmailConfig の設定が必要です。
mfaCodeLength は生成する MFA コードの桁数です。型は number、既定値は 6 です。コードは先頭のゼロを含みうる数値文字列(例: "012345")です。
onetimeTokenSignOptions は MFA チャレンジを含むワンタイムトークンの有効期間を設定します。expiresIn が必須で、既定値は { expiresIn: '5m' } です。
mfaCodeEmailConfig は MFA コード送信用メール設定です。型は { sender: string; emailConfig: { subject: string; bodyTemplate: string } } で、MFA を有効にする場合は必須です。bodyTemplate では ${code} プレースホルダーを使用できます。
MFA フロー: 資格情報の検証後、サービスは期限付きチャレンジトークンと数値コードを生成し、メールでコードを送信します。クライアントはトークンとコードを /auth/mfa/verify に送信し、検証が成功するとアクセストークンとリフレッシュトークンを受け取ります。
🍪 クッキー設定
cookieOpts - HTTP クッキー設定
- 型:
{ domain?: string; maxAge?: string | number; path?: string; sameSite?: 'strict' | 'lax' | 'none' } - 説明: 認証トークンのブラウザクッキーでの保存方法を制御
- 既定:
undefined(トークンの有効期限に準拠) - 子プロパティ:
domain: クッキーのドメイン範囲- 型:
string - 説明: サブドメイン横断の範囲を制御
- 例:
'.example.com'(全サブドメイン)
- 型:
maxAge: クッキーの有効期間- 型:
string | number - 説明: 有効期間(ミリ秒)
- 型:
path: クッキーのパス範囲- 型:
string - 説明: 特定パスに限定
- 既定:
'/'(ドメイン全体) - 例:
'/api'(API のみ)
- 型:
sameSite: CSRF 保護レベル- 型:
'strict' | 'lax' | 'none' - 説明: クロスサイトリクエストでクッキーが送信される条件
- 値:
'strict': 同一サイトのみ送信(最も厳格)'lax': ナビゲーション時に送信(バランス)'none': すべてのクロスサイトで送信(secure: true必須)
- 型:
🔑 JWT 設定
jwtOpts - JWT 生成/検証オプション
- 型:
{ jwtSignOptions?: SignOptions; stateful?: boolean } - 説明: JWT 署名/検証の挙動をカスタマイズ
- 既定:
undefined(標準設定) - 子プロパティ:
jwtSignOptions: JWT 署名設定- 型:
SignOptions(jsonwebtoken) - 説明: 署名アルゴリズムやパラメータの調整
- 既定: 標準署名
- 型:
stateful: サーバー側トークン検証- 型:
boolean - 説明: 失効管理などの強化のためサーバー側で検証
- 既定:
false(ステートレス) - 用途: トークン失効とセキュリティ強化
- 型:
⏰ トークン有効期限
accessTokenExpireTime - アクセストークン寿命
- 型:
string(ms 形式) - 説明: API アクセス用の短寿命トークン
- 既定:
undefined - 形式:
'30m','1h','2h'など(ms 形式) - セキュリティ: 露出時間を最小化
refreshTokenExpireTime - リフレッシュトークン寿命
- 型:
string(ms 形式) - 説明: 再発行用の長寿命トークン
- 既定:
undefined - 形式:
'1d','7d','30d'など(ms 形式) - セキュリティ: HTTP-only/secure クッキーに保存
onetimeTokenExpireTime - ワンタイムトークン寿命
- 型:
string(ms 形式) - 説明: パスワード再設定・メール確認用の一時トークン
- 既定:
undefined - 形式:
'15m','1h','2h'など(ms 形式) - セキュリティ: 1回限り・短寿命
📧 メール確認設定
verifyEmailConfig - メール確認の設定
- 型:
{ enabled: boolean; emailConfig?: EmailConfig; mailService?: MailService; sender: string } - 説明: メール確認機能とテンプレートを制御
- 既定:
undefined(メール確認は無効) - 子プロパティ:
enabled: メール確認機能を有効化- 型:
boolean - 説明: メール確認機能のマスタースイッチ
- 既定:
false - 必須: メール確認を使用する場合は必須
- 型:
emailConfig: メールテンプレート設定- 型:
{ bodyTemplate: string; subject: string; urlTemplate: string } - 説明: 確認メールのテンプレート
- 必須: 有効な場合に必須
- 子プロパティ:
bodyTemplate: HTML メール本文テンプレート- 型:
string - 説明: 本文の HTML テンプレート。
{{url}},{{email}},{{token}}を使用可能。urlにはurlTemplateの値を適用 - 例:
"Hello {{email}}, click <a href=\"{{url}}\">here</a> to verify your email."
- 型:
subject: メール件名- 型:
string - 説明: 確認メールの件名
- 例: "Verify your email address"
- 型:
urlTemplate: 確認リンクの URL テンプレート- 型:
string - 説明:
{{email}}と{{token}}プレースホルダを含む URL テンプレート - 例: "https://yourapp.com/verify?token={{token}}"
- 型:
- 型:
sender: 送信者メールアドレス- 型:
string - 説明: 確認メールの送信元アドレス
- 必須: いいえ(任意)
- 例: "noreply@yourapp.com"
- 型:
| ステータス | エラーメッセージ | 説明 |
|---|---|---|
| 400 | Validation Error | リクエストボディの形式が不正 |
| 400 | verification email feature not enabled | メール確認が未設定 |
| 400 | verification email feature requires a mail service to be provided | メール送信サービスが未設定 |
| 400 | verifyEmailConfig requires emailConfig with fields bodyTemplate, subject, urlTemplate | メール設定が不足 |
| 400 | Unable to verify token | 確認トークンを検証できない |
| 401 | wrong credentials provided | メール/パスワードが不正 |
| 401 | This account is locked | 失敗回数超過によりロック済み |
| 401 | Token is not valid access token | 無効または期限切れのトークン |
| 401 | Token fails security check | トークンのセキュリティ検証に失敗 |
| 401 | token could not be verified | 認可トークンがない/無効 |
| 403 | token does not contain expected data | トークンの内容が期待値に一致しない |
| 403 | User is not authorized to access this resource | 権限不足(管理者アクセスが必要) |
| 404 | User not found | ユーザーが存在しない |
| 404 | Invitation not found | 招待が存在しない |
| 409 | Email already verified or no changes made | メールは既に確認済み |
| 422 | unable to register "email" | メールアドレスは既に存在 |
| 500 | unable to generate access token | アクセストークンの生成に失敗 |
| 500 | unable to generate refresh token | リフレッシュトークンの生成に失敗 |
| 500 | Failed to send verification email | 確認メールの送信に失敗 |
| 400/500 | Failed to create invitation | 招待の作成に失敗 |
🔐 パスワード再設定メール設定
sendResetPasswordEmailConfig はパスワード再設定メールのテンプレートと送信者を設定します。型は { emailConfig: EmailConfig; sender: string } です。emailConfig の bodyTemplate、subject、urlTemplate は必須で、urlTemplate では ${token} を使用できます。既定の本文は Reset your password by clicking ${url} です。
resetPasswordSuccessConfig はパスワード再設定成功通知のテンプレートと送信者を設定します。既定の本文は Your password has been reset です。
changePasswordConfig はパスワード変更通知のテンプレートと送信者を設定します。既定の本文は Your password has been changed です。
deactivateIdentityEmailConfig はアカウント無効化通知のテンプレートと送信者を設定します。サービスには既定値がないため、無効化メールが必要な場合は設定を指定してください。
サービスオプション(第3引数)
interface AuthServiceOptions {
mailService?: MailService; // Mail service implementation
googleOAuthDriver?: GoogleOAuthDriver; // Google OAuth driver instance
}
これらは authService(dataStores, config, options) の第3引数で指定します。
📨 招待設定
invitation - 招待機能の設定
- 型:
{ enabled: boolean; emailConfig?: InvitationEmailConfig; target: string } - 説明: 招待機能とメールテンプレートを制御
- 既定:
undefined(無効) - 子プロパティ:
enabled: 招待機能を有効化- 型:
boolean - 説明: 招待機能のマスタースイッチ
- 既定:
false - 必須: 招待機能を使用する場合は必須
- 型:
emailConfig: 招待メールのテンプレート設定- 型:
{ bodyTemplate: string; subject: string; urlTemplate: string; sender: string } - 説明: 招待メールのテンプレート
- 必須: 有効な場合に必須
- 子プロパティ:
bodyTemplate: HTML メール本文テンプレート- 型:
string - 説明: 本文の HTML テンプレート。
{{url}},{{token}},{{email}}を使用可能。urlにはurlTemplateの値を適用 - 例:
"<h1>You're invited!</h1><p>Click <a href='{{url}}'>here</a> to accept the invitation.</p>"
- 型:
subject: メール件名- 型:
string - 説明: 招待メールの件名
- 例:
"You're invited to join our organization"
- 型:
urlTemplate: 招待リンクの URL テンプレート- 型:
string - 説明:
{{token}}と{{email}}プレースホルダを含む URL テンプレート - 例:
"https://yourapp.com/invitations/accept?token={{token}}&email={{email}}"
- 型:
sender: 送信者メールアドレス- 型:
string - 説明: 招待メールの送信元アドレス
- 必須: 有効な場合に必須
- 例:
"invites@yourapp.com"
- 型:
- 型:
target: 招待検証用トークンのターゲット- 型:
string - 説明: 招待トークン検証のターゲット識別子
- 既定:
"invitation" - 必須: いいえ
- 例:
"invitation"
- 型:
設定例
const authConfig = {
authSecrets: {
authEncSecret: process.env.AUTH_ENC_SECRET || 'your-enc-secret',
authSignSecret: process.env.AUTH_SIGN_SECRET || 'your-sign-secret'
},
maxFailedLoginAttempts: 3,
cookieOpts: {
secure: true,
sameSite: 'strict',
maxAge: 2 * 24 * 60 * 60 * 1000 // 2 days
},
accessTokenExpireTime: '1h',
refreshTokenExpireTime: '7d',
onetimeTokenExpireTime: '30m',
verifyEmailConfig: {
enabled: true,
emailConfig: {
bodyTemplate: 'Hello {{email}}, click <a href="{{url}}">here</a> to verify your email address.',
subject: 'Verify your email address',
urlTemplate: 'https://yourapp.com/verify?token={{token}}'
},
sender: 'noreply@yourapp.com'
},
invitation: {
enabled: true,
emailConfig: {
bodyTemplate: '<h1>You\'re invited!</h1><p>Click <a href="{{url}}">here</a> to accept the invitation.</p>',
subject: 'You\'re invited to join our organization',
urlTemplate: 'https://yourapp.com/invitations/accept?token={{token}}&email={{email}}',
sender: 'invites@yourapp.com'
},
target: 'invitation'
}
};
🚨 エラーハンドリング
認証関連のエラーは、適切なHTTPステータスコードとJSON形式で返されます。
代表的なエラーコード
| ステータス | エラーメッセージ | 説明 |
|---|---|---|
| 400 | Validation Error | リクエスト本文の形式が無効 |
| 400 | verification email feature not enabled | メール認証が設定されていない |
| 400 | verification email feature requires a mail service to be provided | メールサービスが設定されていない |
| 400 | verifyEmailConfig requires emailConfig with fields bodyTemplate, subject, urlTemplate | メール設定が不足している |
| 400 | Unable to verify token | 認証トークンが無効 |
| 401 | wrong credentials provided | メールアドレスまたはパスワードが無効 |
| 401 | This account is locked | 失敗回数によりアカウントがロックされている |
| 401 | Token is not valid access token | トークンが無効または期限切れ |
| 401 | Token fails security check | トークンのセキュリティ検証に失敗 |
| 401 | Unable to detect access token | アクセストークンがない |
| 403 | token does not contain expected data | トークンの検証に失敗 |
| 403 | Identity is not authorized to access this resource | アイデンティティに必要な権限(管理者アクセス)がない |
| 404 | Identity not found | アイデンティティが存在しない |
| 404 | Invitation not found | 招待が存在しない |
| 409 | Email already verified or no changes made | メールアドレスはすでに認証済み |
| 422 | unable to register "<email>" | メールアドレスがすでに存在する |
| 500 | unable to generate access token | トークンの生成に失敗 |
| 500 | unable to generate refresh token | リフレッシュトークンの生成に失敗 |
| 500 | Failed to send verification email | メール送信処理に失敗 |
| 500 | Invitation email configuration is incomplete or disabled | 招待メール設定またはメールサービスを利用できない |
エラーレスポンス形式
以下は個別の認証フローで返される代表的なエラーペイロードです。message はサーバーから返される技術リテラルのため変更しません。
{ "error": { "message": "wrong credentials provided" } }
{ "error": { "message": "This account is locked" } }
{ "error": { "message": "Token is not valid access token" } }
{ "error": { "message": "Token fails security check" } }
{ "error": { "message": "token does not contain expected data" } }
{ "error": { "message": "Invitation not found" } }
{ "error": { "message": "Email already verified or no changes made" } }
{ "error": { "message": "unable to generate access token" } }
{ "error": { "message": "unable to generate refresh token" } }
{ "error": { "message": "Failed to create invitation" } }
{ "error": { "message": "Unable to verify token" } }
{
"error": {
"message": "Error message description",
"data": ["Additional error details"]
}
}
🔗 関連ドキュメント
- プロフィールサービス - プロフィール管理
- エラーハンドリング - エラーミドルウェアと処理