コンテンツにスキップ

設定スキーマ

Authrimのプラグイン設定は、検証とAdmin UIの自動生成にZodスキーマを使用します。このガイドでは設定スキーマ定義のベストプラクティスを説明します。

すべてのプラグインはZodを使用してconfigSchemaを定義する必要があります:

import { z } from 'zod';
const configSchema = z.object({
apiKey: z.string().min(1),
timeout: z.number().int().min(1000).max(30000).default(10000),
retries: z.number().int().min(0).max(5).default(3),
enabled: z.boolean().default(true),
});
type MyConfig = z.infer<typeof configSchema>;

.describe()を使用してAdmin UI用のラベルとヘルプテキストを提供します:

const configSchema = z.object({
apiKey: z
.string()
.min(1)
.describe('プロバイダーダッシュボードからのAPIキー'),
endpoint: z
.string()
.url()
.default('https://api.example.com')
.describe('APIエンドポイントURL。カスタムサーバー使用時のみ変更してください。'),
timeout: z
.number()
.int()
.min(1000)
.max(30000)
.default(10000)
.describe('リクエストタイムアウト(ミリ秒)(1000-30000)'),
logLevel: z
.enum(['debug', 'info', 'warn', 'error'])
.default('info')
.describe('ログの詳細レベル'),
});

Admin UIはこれらの説明に基づいてフォームを自動生成します:

フィールドタイプUIコンポーネント
z.string()テキスト入力
z.string().url()URL入力
z.number()数値入力
z.boolean()トグルスイッチ
z.enum([...])ドロップダウン選択
機密名を持つz.string()パスワード入力

Authrimは以下のパターンに一致するフィールドを自動的に検出し、PLUGIN_ENCRYPTION_KEY または KEY_MANAGER_SECRET が設定されている場合に暗号化します:

  • apiKey, apiSecret
  • secretKey, clientSecret
  • password, token
  • authToken, accessToken, refreshToken
  • privateKey, credential

暗号化keyが利用できない場合でもAdmin APIのwriteは継続し、値は平文で保存され、warning logが出ます。本番secretを保存する前に暗号化keyを設定してください。

const configSchema = z.object({
// 自動的に検出されて暗号化
apiKey: z.string().describe('あなたのAPIキー'),
clientSecret: z.string().describe('OAuthクライアントシークレット'),
authToken: z.string().describe('認証トークン'),
// 暗号化されない(パターンに一致しない)
endpoint: z.string().url(),
timeout: z.number(),
});

カスタムの機密フィールド名の場合は、APIリクエストで指定します:

Terminal window
curl -X PUT "/api/admin/plugins/my-plugin/config" \
-H "Content-Type: application/json" \
-d '{
"config": {
"customCredential": "super-secret-value",
"endpoint": "https://api.example.com"
},
"secret_fields": ["customCredential"]
}'

機密値はすべてのAPIレスポンスでマスキングされます:

{
"config": {
"apiKey": "sk_l****XYZ1",
"clientSecret": "cs_a****bcde",
"endpoint": "https://api.example.com"
}
}

マスキング形式:

  • 先頭4文字と末尾4文字を表示(例:sk_l****XYZ1
  • 短い値は完全にマスク ****

プラグインスキーマはAdmin UI用にJSONスキーマに自動変換されます:

// Zodスキーマ
const configSchema = z.object({
apiKey: z.string().min(1).describe('あなたのAPIキー'),
timeout: z.number().min(1000).max(30000).default(10000),
algorithm: z.enum(['sha1', 'sha256', 'sha512']).default('sha256'),
});
// JSONスキーマに変換
{
"type": "object",
"properties": {
"apiKey": {
"type": "string",
"minLength": 1,
"description": "あなたのAPIキー"
},
"timeout": {
"type": "number",
"minimum": 1000,
"maximum": 30000,
"default": 10000
},
"algorithm": {
"type": "string",
"enum": ["sha1", "sha256", "sha512"],
"default": "sha256"
}
},
"required": ["apiKey"]
}

Plugin Management Admin APIは以下の順序で設定を解決します:

┌─────────────────────────────────────────┐
│ 1. 環境変数 + built-in env値 │
├─────────────────────────────────────────┤
│ 2. KVストレージ(グローバル設定) │
├─────────────────────────────────────────┤
│ 3. KVストレージ(テナント固有override) │
├─────────────────────────────────────────┤
│ 4. plugin schema default(parse時) │
└─────────────────────────────────────────┘

Runtime plugin loaderはresolved plugin registry/configをcacheすることがあります。Admin APIのconfig、enable、disable endpointへのwrite後は、対象pluginとtenant scopeのplugin runtime cacheがinvalidateされます。

Terminal window
# 形式: PLUGIN_{PLUGIN_ID}_CONFIG=<JSON>
PLUGIN_NOTIFIER_RESEND_CONFIG='{"apiKey":"re_xxx","defaultFrom":"[email protected]"}'
# ハイフン付きのプラグインIDはアンダースコアになる
PLUGIN_NOTIFIER_CLOUDFLARE_CONFIG='{"defaultFrom":"[email protected]","fromName":"Authrim"}'

組み込みnotifier pluginはdeployment env値からもbootstrapできます。たとえば notifier-resendRESEND_API_KEYEMAIL_FROMnotifier-cloudflareEMAIL_FROMEMAIL_FROM_NAME を読み、その後KV overrideが適用されます。

キーパターン説明
plugins:config:{pluginId}グローバル設定
plugins:config:{pluginId}:tenant:{tenantId}テナント固有のオーバーライド
plugins:enabled:{pluginId}グローバル有効/無効
plugins:enabled:{pluginId}:tenant:{tenantId}テナント有効/無効
// グローバル設定
const globalConfig = {
apiKey: 'default-api-key',
defaultFrom: '[email protected]',
};
// テナントAはFromアドレスのみオーバーライド
const tenantAConfig = {
defaultFrom: '[email protected]',
};
// テナントAの解決された設定(マージ)
{
apiKey: 'default-api-key', // グローバルから
defaultFrom: '[email protected]' // テナントから
}
Terminal window
# platform settings screenからtenant固有設定を取得
curl "/api/admin/platform/plugins/notifier-resend/config?tenant_id=tenant_123"
# platform settings screenからtenant固有設定を更新
curl -X PUT "/api/admin/platform/plugins/notifier-resend/config" \
-d '{"config": {"defaultFrom": "[email protected]"}, "tenant_id": "tenant_123"}'

Tenant-facing /api/admin/plugins/... routeは現在のtenant contextを使います。tenant_id を明示的に渡す必要がある場合は /api/admin/platform/plugins/... を使ってください。

設定構造はフラットまたは浅いネストに保ちます:

// ✅ 良い例:フラットまたは浅いネスト
const configSchema = z.object({
apiKey: z.string(),
smtp: z.object({
host: z.string(),
port: z.number(),
secure: z.boolean(),
}),
retries: z.object({
max: z.number().default(3),
delay: z.number().default(1000),
}),
});
// ❌ 悪い例:過度に深いネスト
const badConfigSchema = z.object({
level1: z.object({
level2: z.object({
level3: z.object({
// ... 20レベル以上 - 機密情報がマスクされない!
}),
}),
}),
});
const configSchema = z.object({
// 必須(デフォルトなし)
apiKey: z.string().min(1),
// デフォルト付きオプション
timeout: z.number().default(10000),
// デフォルトなしオプション
webhook: z.string().url().optional(),
// nullableオプション
fallbackUrl: z.string().url().nullable().default(null),
});
const configSchema = z.object({
// 異なる認証方式
auth: z.union([
z.object({
type: z.literal('api_key'),
apiKey: z.string(),
}),
z.object({
type: z.literal('oauth'),
clientId: z.string(),
clientSecret: z.string(),
}),
]),
});
const configSchema = z.object({
useTLS: z.boolean().default(true),
tlsCert: z.string().optional(),
tlsKey: z.string().optional(),
}).refine(
(data) => !data.useTLS || (data.tlsCert && data.tlsKey),
{ message: 'TLSが有効な場合、証明書と鍵が必要です' }
);
const configSchema = z.object({
endpoints: z
.array(z.string().url())
.min(1)
.max(5)
.describe('APIエンドポイントのリスト(1-5)'),
allowedDomains: z
.array(z.string())
.default([])
.describe('コールバックに許可されるドメイン'),
});
const configSchema = z.object({
// セキュアなデフォルト
timeout: z.number().default(10000), // 10秒
retries: z.number().default(3),
validateCerts: z.boolean().default(true), // セキュリティ:常に検証
// 本番環境で安全なデフォルト
logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
rateLimit: z.number().default(60),
});
const configSchema = z.object({
timeout: z
.number()
.int()
.min(1000)
.max(30000)
.default(10000)
.describe('リクエストタイムアウト(ms)(1000-30000)。低速ネットワークでは増加。'),
batchSize: z
.number()
.int()
.min(1)
.max(100)
.default(10)
.describe('バッチあたりのアイテム数(1-100)。大きい値はメモリを多く使用。'),
});
const configSchema = z.object({
// 接続設定
host: z.string().default('smtp.example.com'),
port: z.number().default(587),
secure: z.boolean().default(true),
// 認証
username: z.string().optional(),
password: z.string().optional(),
// メッセージのデフォルト
defaultFrom: z.string().email(),
defaultReplyTo: z.string().email().optional(),
});