🔐 認証ユーティリティ
Nodeblocks SDK は、トークン管理、検証、セキュリティのための包括的な認証ユーティリティを提供します。これらのユーティリティは、Bearer トークン、Cookie ベース認証、およびさまざまなユースケース向けの各種トークンタイプを処理します。
🎯 概要
認証ユーティリティは、ユーザーおよびアプリケーション認証の両方に対し、安全なトークン生成、検証、管理を提供します。複数のトークンタイプとセキュリティ検証メカニズムをサポートします。
サービスレベルの構成(authMode、checkIp、トークン署名オプション)については、Authentication サービスを参照してください。
主な機能
- 複数のトークンタイプ: ユーザーアクセス、アプリアクセス、リフレッシュ、ワンタイムトークン
- セキュリティ検証: フィンガープリント、IP、ユーザーエージェントの検証
- 柔軟な認証: Bearer トークンおよび Cookie ベース認証
- 二層トークン: 署名済み JWT を囲む AES-256-CBC 暗号化エンベロープ
トークン形式
トークンは二層形式を使用します:
- 内側の層:
authSignSecretで署名した標準 JWT(jsonwebtokenを使用) - 外側の層:
authEncSecretから SHA-256 で導出したキーによる AES-256-CBC 暗号化。iv_hex:ciphertext_hexとして保存されます
エンベロープには encrypt/decrypt を使用し、復号と検証を一度に行うには decryptAndVerifyJWT を使用します。
デフォルトのトークン有効期間
| トークン | デフォルトの expiresIn |
|---|---|
| ユーザーアクセス | '15m' |
| Refresh | '2d' |
| ワンタイム | '5m' |
| アプリアクセス | なし(署名オプションにデフォルトの有効期限はありません) |
🔑 トークン生成
generateUserAccessToken
セキュリティ検証メタデータを含む暗号化ユーザーアクセストークンを作成します。
import { utils } from '@nodeblocks/backend-sdk';
const { generateUserAccessToken } = utils;
const token = generateUserAccessToken(
authSecrets,
{ expiresIn: '30m' }, // optional; default '15m'
identityId,
{
fingerprint: 'device-fingerprint',
ip: '192.168.1.1',
domain: 'example.com',
userAgent: 'Mozilla/5.0...'
}
);
パラメーター:
authSecrets: 暗号化/署名用の認証シークレットjwtSignOptions:jsonwebtokenの必須SignOptions | undefinedパラメーター。デフォルトのexpiresIn: '15m'を使用するにはundefinedを渡しますidentityId: アイデンティティ識別子tokenVerification: 検証用セキュリティコンテキスト
注記:
- 生成トークンは常に
stateful: falseです(この関数では設定不可)
generateAppAccessToken
サービス間通信向けの暗号化アプリアクセストークンを作成します。
import { utils } from '@nodeblocks/backend-sdk';
const { generateAppAccessToken } = utils;
const token = generateAppAccessToken(authSecrets, 'app-service-id');
パラメーター:
authSecrets: 認証シークレットappId: アプリケーション識別子
generateRefreshToken
セッション管理用の暗号化リフレッシュトークンを作成します。
import { utils } from '@nodeblocks/backend-sdk';
const { generateRefreshToken } = utils;
const token = generateRefreshToken(
authSecrets,
'jwt-token-id',
identityId,
{
fingerprint: 'device-fingerprint',
ip: '192.168.1.1',
domain: 'example.com',
userAgent: 'Mozilla/5.0...'
},
{ expiresIn: '7d' } // optional; default '2d'
);
パラメーター:
authSecrets: 認証シークレットjti: ステートフルリフレッシュトークン追跡用 JWT トークン IDidentityId: アイデンティティ識別子tokenVerification: 検証用セキュリティコンテキストjwtSignOptions: 任意のSignOptions(デフォルトexpiresIn: '2d')
注記:
- 生成トークンは常に
stateful: trueです(ハードコードされ、この関数では設定不可)
generateOnetimeToken
一時アクセス用のワンタイムトークンを作成します。
import { utils } from '@nodeblocks/backend-sdk';
const { generateOnetimeToken } = utils;
const token = generateOnetimeToken(
authSecrets,
{ identityId: 'id-123', action: 'password-reset' },
{
fingerprint: 'device-fingerprint',
ip: '192.168.1.1',
domain: 'example.com',
userAgent: 'Mozilla/5.0...'
},
{ expiresIn: '1h' } // optional; default '5m'
);
パラメーター:
authSecrets: 認証シークレットdata: トークンに埋め込むペイロード(Record<string, unknown>)tokenVerification: 検証用セキュリティコンテキストjwtSignOptions: 任意のSignOptions(デフォルトexpiresIn: '5m')
注記:
- 生成トークンは常に
stateful: trueです(ハードコードされ、この関数では設定不可)
🔍 トークン検証
getBearerTokenInfo
リクエストの Authorization ヘッダーからトークン情報を抽出します。Bearer トークン用のデフォルト認証関数です。
import { utils } from '@nodeblocks/backend-sdk';
const { getBearerTokenInfo } = utils;
const tokenInfo = await getBearerTokenInfo(payload);
処理:
Authorization: Bearer <token>ヘッダーからトークンを抽出します- JWT 署名を復号して検証します
- トークンタイプ(ユーザーまたはアプリ)を検証します
- ユーザートークンのセキュリティチェックを実行します(アプリトークンはセキュリティチェックを省略します)
- トークン情報を返します
IP バインディング: payload.context.configuration.checkIp で制御します。未設定時、IP チェックはデフォルトで有効です(checkIp ?? true)。
エラー: トークンが欠落、不正、アクセストークンでない、またはセキュリティチェックに失敗した場合(ユーザートークン)、NodeblocksError(401) をスローします。アプリアクセストークンはセキュリティチェックを省略し、AppAccessTokenInfo を返します。
getCookieTokenInfo
Cookie からトークン情報を抽出します。authMode が 'cookie' のときの Cookie ベーストークン用認証関数です。
import { utils } from '@nodeblocks/backend-sdk';
const { getCookieTokenInfo } = utils;
const tokenInfo = await getCookieTokenInfo(payload);
ユースケース:
- Cookie ベース認証を使用する Web アプリケーション(
cookies.accessToken) cookie-parserを使用するサーバーサイドセッション管理
注: Cookie モードと Bearer モードの違いはトークン転送のみです。セキュリティチェック(フィンガープリント、IP、ユーザーエージェント)は、configuration.checkIp ?? true を含め、getBearerTokenInfo と同じロジックを使用します。
エラー: cookies.accessToken が欠落、不正、アクセストークンでない、またはセキュリティチェックに失敗した場合(ユーザートークン)、NodeblocksError(401) をスローします。アプリアクセストークンはセキュリティチェックを省略し、AppAccessTokenInfo を返します。
defaultRefreshTokenBodyAuth
リクエスト本文から取得するリフレッシュトークン用のデフォルト認証関数です。常にトークンを抽出し、decryptToken が true の場合は復号、検証、セキュリティチェックを行います。
import { utils } from '@nodeblocks/backend-sdk';
const { defaultRefreshTokenBodyAuth } = utils;
const { token, tokenInfo } = await defaultRefreshTokenBodyAuth(
authSecrets,
request,
true, // decryptToken
logger
);
パラメーター:
authSecrets: トークン復号用の認証シークレットrequest: リフレッシュトークンを含む HTTP リクエストオブジェクトdecryptToken: トークンを復号および検証するか(デフォルト: false)logger: セキュリティチェックログ用の任意ロガー
処理:
request.body.refreshTokenからリフレッシュトークンを抽出します- トークン検証コンテキスト(フィンガープリント、IP、ユーザーエージェント)を取得します
- トークン形式と存在を検証します
- JWT 署名を復号して検証します(
decryptTokenが true の場合) - トークンタイプがリフレッシュトークンであることを検証します
- IP 検証を有効にしてセキュリティチェックを実行します
- トークンおよびトークン情報を返します
defaultRefreshTokenCookieAuth
Cookie から取得するリフレッシュトークン用のデフォルト認証関数です。常にトークンを抽出し、decryptToken が true の場合は復号、検証、セキュリティチェックを行います。そのモードでは token と tokenInfo の両方を返します。
import { utils } from '@nodeblocks/backend-sdk';
const { defaultRefreshTokenCookieAuth } = utils;
const { token, tokenInfo } = await defaultRefreshTokenCookieAuth(
authSecrets,
request,
true, // decryptToken
logger
);
パラメーター:
authSecrets: トークン復号用の認証シークレットrequest: Cookie 内のリフレッシュトークンを含む HTTP リクエストオブジェクトdecryptToken: トークンを復号および検証するか(デフォルト: false)logger: セキュリティチェックログ用の任意ロガー
処理:
request.cookies.refreshTokenからリフレッシュトークンを抽出します- トークン検証コンテキスト(フィンガープリント、IP、ユーザーエージェント)を取得します
- トークン形式と存在を検証します
- JWT 署名を復号して検証します(
decryptTokenが true の場合) - トークンタイプがリフレッシュトークンであることを検証します
- IP 検証を有効にしてセキュリティチェックを実行します(
checkIp: true) - トークンおよびトークン情報を返します(
decryptTokenが true の場合)
本文認証との主な違い:
- ソース: リクエスト本文ではなく Cookie から読み取ります
resolveRefreshTokenFromRequest
Cookie および/またはリクエスト本文からリフレッシュトークンを解決します。両方のソースが存在する場合、同じトークンを指す必要があります。
import { utils } from '@nodeblocks/backend-sdk';
const { resolveRefreshTokenFromRequest } = utils;
const result = await resolveRefreshTokenFromRequest(authSecrets, request, logger);
if (result.isOk() && result.value) {
const { token, tokenInfo } = result.value;
}
パラメーター:
authSecrets: トークン復号用の認証シークレットrequest: HTTP リクエストオブジェクトlogger: セキュリティチェックログ用の任意ロガー
戻り値:
Result<{ token: string; tokenInfo: RefreshTokenInfo } | undefined, NodeblocksError>- 有効なリフレッシュトークンが見つからない場合は
ok(undefined)を返します - Cookie と本文のトークンが一致しない場合は、401 の
err(...)を返します
🛡️ セキュリティ関数
tokenPassesSecurityCheck
トークンのセキュリティコンテキストを検証します。
import { utils } from '@nodeblocks/backend-sdk';
const { tokenPassesSecurityCheck } = utils;
const isValid = tokenPassesSecurityCheck(
tokenInfo,
{
fingerprint: 'device-fingerprint',
ip: '192.168.1.1',
userAgent: 'Mozilla/5.0...'
},
logger,
{ checkIp: true }
);
検証ロジック:
- フィンガープリントは一致する必要があります。一致しない場合、チェックは直ちに失敗します
checkIpが無効の場合、チェックは成功します(フィンガープリントはすでに一致しています)checkIpが有効で IP が一致する場合、チェックは成功しますcheckIpが有効で IP が一致しない場合、ユーザーエージェントが一致するときにのみチェックは成功します。それ以外は失敗します
パラメーター:
tokenInfo: ユーザーアクセスまたはリフレッシュトークン情報tokenVerification: 現在のリクエストコンテキスト(domain、fingerprint、ip、userAgent)logger: 任意のロガーoptions.checkIp: IP バインディングチェックを実行するか(デフォルト:true)
decryptAndVerifyJWT
AES エンベロープを復号し、内側の JWT 署名を検証します。
import { utils } from '@nodeblocks/backend-sdk';
const { decryptAndVerifyJWT } = utils;
const tokenInfo = decryptAndVerifyJWT(authSecrets, encryptedToken);
エラー: トークンが空、形式不正、不正、または期限切れの場合、ステータス 401 の NodeblocksError をスローします。フィンガープリント/IP/ユーザーエージェントチェックは実行しません。呼び出し元(例: 認証関数)は、ユーザートークンに対して別途 tokenPassesSecurityCheck を実行する必要があります。
🔧 ヘルパー関数
getBearerToken
リクエストヘッダーから Bearer トークンを抽出します。
import { utils } from '@nodeblocks/backend-sdk';
const { getBearerToken } = utils;
const token = getBearerToken(request.headers);
// Returns: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
エラー: Authorization ヘッダーがない場合は undefined を返します。ヘッダーが存在するものの文字列でない、または Bearer <token> 形式でない場合は、ステータス 422 の NodeblocksError をスローします。
getFingerprint
ヘッダーからデバイスフィンガープリントを抽出します。
import { utils } from '@nodeblocks/backend-sdk';
const { getFingerprint } = utils;
const fingerprint = getFingerprint(request.headers, 'x-nb-fingerprint');
エラー: ヘッダーが存在するものの文字列でない場合、ステータス 422 の NodeblocksError をスローします。
getUserAgent
リクエストヘッダーからユーザーエージェントを抽出します。
import { utils } from '@nodeblocks/backend-sdk';
const { getUserAgent } = utils;
const userAgent = getUserAgent(request.headers);
getRequestInfo
トークン検証用のリクエストメタデータを抽出します。
import { utils } from '@nodeblocks/backend-sdk';
const { getRequestInfo } = utils;
const requestInfo = getRequestInfo(request);
// Returns: { host, ip, method, path, url }
getExpiresIn
トークンの有効期限値を正規化します。さまざまな入力形式を標準化された有効期限形式に変換します。
import { utils } from '@nodeblocks/backend-sdk';
const { getExpiresIn } = utils;
const expiresIn = getExpiresIn('24h'); // Returns: '24h'
const expiresIn2 = getExpiresIn(3600000); // Returns: 3600000
const expiresIn3 = getExpiresIn(); // Returns: '48h' (default)
パラメーター:
expirationTime: 文字列または数値として指定する任意の有効期限
戻り値:
number | string: 正規化済み有効期限(デフォルト: '48h')
動作:
expirationTimeがnullまたはundefinedの場合: デフォルトの '48h' を返しますexpirationTimeが有効な数値の場合: その数値を返しますexpirationTimeが非数値文字列の場合: 文字列をそのまま返しますexpirationTimeが数値文字列の場合: 数値に変換します
getExpirationDate
期間文字列またはミリ秒に基づいて絶対有効期限日時を計算します。
import { utils } from '@nodeblocks/backend-sdk';
const { getExpirationDate } = utils;
const expirationDate = getExpirationDate('7d'); // Returns: Date object 7 days from now
const expirationDate2 = getExpirationDate(3600000); // Returns: Date object 1 hour from now
const expirationDate3 = getExpirationDate(); // Returns: Date object 2 days from now (default)
パラメーター:
expiresIn: 期間文字列(例: '7d'、'24h'、'30m')またはミリ秒(デフォルト:'2d')
戻り値:
Date: 絶対有効期限日時
対応する期間形式:
'7d'- 7 日'24h'- 24 時間'30m'- 30 分'60s'- 60 秒- ミリ秒の数値
deriveCookieMaxAge
トークンの expiresIn 値を Express Cookie の maxAge オプション用のミリ秒に変換します。
import { utils } from '@nodeblocks/backend-sdk';
const { deriveCookieMaxAge } = utils;
const maxAge = deriveCookieMaxAge('15m'); // Returns: 900000 (ms)
const maxAge2 = deriveCookieMaxAge(3600); // Returns: 3600000 (3600 seconds → ms)
パラメーター:
expiresIn: 期間文字列(ms()で解析)、または 秒単位の数値(jsonwebtokenの規約に準拠)
戻り値:
number: ミリ秒単位の期間
注: getExpirationDate と異なり、ここでは単独の数値をミリ秒ではなく秒として扱います。
isAccessToken
トークンがアクセストークン(ユーザーまたはアプリ)かどうかを確認し、単純な型ガードとして使用できます。
import { utils } from '@nodeblocks/backend-sdk';
const { isAccessToken } = utils;
if (isAccessToken(tokenInfo)) {
// tokenInfo is AccessTokenInfo (accessType: 'user' | 'app')
}
パラメーター:
tokenInfo: 確認するトークン情報オブジェクト
戻り値:
boolean: トークンがアクセストークンならtrue、それ以外はfalse
isUserAccessToken
トークンがユーザーアクセストークンかどうかを確認します。
import { utils } from '@nodeblocks/backend-sdk';
const { isUserAccessToken } = utils;
if (isUserAccessToken(tokenInfo)) {
// tokenInfo is UserAccessTokenInfo
console.log(tokenInfo.identityId);
}
パラメーター:
tokenInfo: 確認するトークン情報オブジェクト
戻り値:
boolean: トークンがユーザーアクセストークンならtrue、それ以外はfalse
isAppAccessToken
トークンがアプリアクセストークンかどうかを確認します。
import { utils } from '@nodeblocks/backend-sdk';
const { isAppAccessToken } = utils;
if (isAppAccessToken(tokenInfo)) {
// tokenInfo is AppAccessTokenInfo
console.log(tokenInfo.appId);
}
パラメーター:
tokenInfo: 確認するトークン情報オブジェクト
戻り値:
boolean: トークンがアプリアクセストークンならtrue、それ以外はfalse
isRefreshToken
トークンがリフレッシュトークンかどうかを確認します。
import { utils } from '@nodeblocks/backend-sdk';
const { isRefreshToken } = utils;
if (isRefreshToken(tokenInfo)) {
// tokenInfo is RefreshTokenInfo
console.log(tokenInfo.jti);
}
パラメーター:
tokenInfo: 確認するトークン情報オブジェクト
戻り値:
boolean: トークンがリフレッシュトークンならtrue、それ以外はfalse
isOnetimeToken
トークンがワンタイムトークンかどうかを確認します。
import { utils } from '@nodeblocks/backend-sdk';
const { isOnetimeToken } = utils;
if (isOnetimeToken(tokenInfo)) {
// tokenInfo is OnetimeTokenInfo
console.log(tokenInfo.data);
}
パラメーター:
tokenInfo: 確認するトークン情報オブジェクト
戻り値:
boolean: トークンがワンタイムトークンならtrue、それ以外はfalse
isValidAppAccessToken
アプリアクセストークンに appId が存在することを確認します。
import { utils } from '@nodeblocks/backend-sdk';
const { isValidAppAccessToken } = utils;
if (isValidAppAccessToken(tokenInfo)) {
// tokenInfo is AppAccessTokenInfo with appId present
}
パラメーター:
tokenInfo: 確認するトークン情報オブジェクト
戻り値:
boolean:appIdを持つアプリアクセストークンならtrue、それ以外はfalse
isValidUserAccessToken
ユーザーアクセストークンに identityId が存在することを確認します。
import { utils } from '@nodeblocks/backend-sdk';
const { isValidUserAccessToken } = utils;
if (isValidUserAccessToken(tokenInfo)) {
// tokenInfo is UserAccessTokenInfo with identityId present
}
パラメーター:
tokenInfo: 確認するトークン情報オブジェクト
戻り値:
boolean:identityIdを持つユーザーアクセストークンならtrue、それ以外はfalse
retrieveTokenVerification
Express の Request からトークン検証メタデータを作成します。
import { utils } from '@nodeblocks/backend-sdk';
const { retrieveTokenVerification } = utils;
const verification = retrieveTokenVerification(request);
// { domain, fingerprint, ip, userAgent }
validateAuthSecrets
必須の認証シークレットを検証し、欠落または短すぎる場合はスローします。
import { utils } from '@nodeblocks/backend-sdk';
const { validateAuthSecrets } = utils;
validateAuthSecrets(authSecrets); // throws on invalid configuration
validateAuthSecrets(authSecrets, 24); // optional minimum length (default: 18)
エラー: シークレットが欠落している、または最小長より短い場合、ステータス 500 の NodeblocksError をスローします。
generateMailBody
URL とオプションをメールテンプレートに補間します。
import { utils } from '@nodeblocks/backend-sdk';
const { generateMailBody } = utils;
const body = generateMailBody(
'Click here: ${url}',
'https://example.com/reset?token=${token}',
{ token: 'abc' }
);
authSecretsValidationErrorMessage
無効な認証シークレットに対する人間可読なエラーを返します(一時的なヘルパー)。
import { utils } from '@nodeblocks/backend-sdk';
const { authSecretsValidationErrorMessage } = utils;
const msg = authSecretsValidationErrorMessage(authSecrets);
if (msg) throw new Error(msg);
// Optional minimum length (default: 18)
const msg2 = authSecretsValidationErrorMessage(authSecrets, 24);
🔐 暗号化関数
encrypt
AES-256-CBC を使用して文字列を暗号化します。iv_hex:ciphertext_hex を返します。
import { utils } from '@nodeblocks/backend-sdk';
const { encrypt } = utils;
const encrypted = encrypt(authSecrets.authEncSecret, 'sensitive-data');
decrypt
AES-256-CBC エンベロープ(iv_hex:ciphertext_hex)を復号します。
import { utils } from '@nodeblocks/backend-sdk';
const { decrypt } = utils;
const decrypted = decrypt(authSecrets.authEncSecret, encryptedData);
エラー: 入力が空、形式不正、または不正の場合、ステータス 401 の NodeblocksError をスローします。
🔑 パスワード関数
hash
コスト係数 10 の bcrypt を使用してパスワードをハッシュ化します。
import { utils } from '@nodeblocks/backend-sdk';
const { hash } = utils;
const hashedPassword = await hash('user-password');
実装: 10 回のソルトラウンドで bcrypt を使用します(bcryptHash(s, 10))。
compareHash
パスワードとハッシュを比較します。
import { utils } from '@nodeblocks/backend-sdk';
const { compareHash } = utils;
const isValid = await compareHash('user-password', hashedPassword);
📊 トークンタイプ
トークンインターフェースは utils ではなく、types 名前空間(ソース: src/types/authentication.ts)からエクスポートされます:
import { types } from '@nodeblocks/backend-sdk';
type UserAccessTokenInfo = types.UserAccessTokenInfo;
type AppAccessTokenInfo = types.AppAccessTokenInfo;
type RefreshTokenInfo = types.RefreshTokenInfo;
type OnetimeTokenInfo = types.OnetimeTokenInfo;
ユーザーアクセストークン
interface UserAccessTokenInfo {
accessType: 'user';
identityId: string;
type: 'access';
stateful: boolean;
fingerprint?: string;
ip?: string;
domain?: string;
target?: string;
userAgent?: string;
}
アプリアクセストークン
interface AppAccessTokenInfo {
accessType: 'app';
appId: string;
type: 'access';
}
リフレッシュトークン
interface RefreshTokenInfo {
type: 'refresh';
jti: string;
identityId: string;
stateful: true;
fingerprint?: string;
ip?: string;
domain?: string;
userAgent?: string;
}
ワンタイムトークン
interface OnetimeTokenInfo {
type: 'onetime';
data: Record<string, unknown>;
stateful: true;
fingerprint?: string;
ip?: string;
domain?: string;
target?: string;
userAgent?: string;
}