Hono、Koa & NestJSアダプター
概要
@authrim/server は Hono、Koa、NestJS 向けのアダプターを提供します。各アダプターはアクセストークン(BearerおよびDPoP)を検証し、フレームワーク固有の慣用的なパターンで認証済みユーザーコンテキストを公開します。
ExpressとFastifyについては、Express & Fastifyアダプターを参照してください。
Honoアダプター
@authrim/server/adapters/hono からインポートします。
Honoは認証データに(リクエストプロパティへの直接設定ではなく)コンテキスト変数を使用します。アクセスには getAuth() と getAuthTokenType() ヘルパー関数を使用してください。
authrimMiddleware()
必須認証 — 未認証のリクエストに401を返します:
import { Hono } from 'hono';import { createAuthrimServer } from '@authrim/server';import { authrimMiddleware, getAuth, getAuthTokenType,} from '@authrim/server/adapters/hono';
const server = createAuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com',});
const app = new Hono();
// Protect all routes under /apiapp.use('/api/*', authrimMiddleware(server));
app.get('/api/profile', (c) => { const auth = getAuth(c); // ValidatedToken (guaranteed) const type = getAuthTokenType(c); // 'Bearer' | 'DPoP'
return c.json({ sub: auth.sub, tokenType: type });});authrimOptionalMiddleware()
オプション認証 — 未認証のリクエストでも処理を続行します:
import { authrimOptionalMiddleware, getAuth,} from '@authrim/server/adapters/hono';
app.get('/api/feed', authrimOptionalMiddleware(server), (c) => { const auth = getAuth(c);
if (auth) { return c.json({ feed: getPersonalizedFeed(auth.sub) }); } return c.json({ feed: getPublicFeed() });});ヘルパー関数
| 関数 | 戻り値の型 | 説明 |
|---|---|---|
getAuth(c) | ValidatedToken | undefined | Honoコンテキストから検証済みトークンを取得 |
getAuthTokenType(c) | 'Bearer' | 'DPoP' | undefined | Honoコンテキストからトークンタイプを取得 |
Cloudflare Workersサンプル
HonoはCloudflare Workersにデプロイされることが多いフレームワークです。以下に完全なサンプルを示します:
import { Hono } from 'hono';import { createAuthrimServer } from '@authrim/server';import { authrimMiddleware, authrimOptionalMiddleware, getAuth,} from '@authrim/server/adapters/hono';
type Bindings = { AUTHRIM_ISSUER: string; AUTHRIM_AUDIENCE: string;};
const app = new Hono<{ Bindings: Bindings }>();
app.use('/api/*', async (c, next) => { const server = createAuthrimServer({ issuer: c.env.AUTHRIM_ISSUER, audience: c.env.AUTHRIM_AUDIENCE, });
return authrimMiddleware(server)(c, next);});
app.get('/api/profile', (c) => { const auth = getAuth(c); return c.json({ sub: auth!.sub });});
app.get('/health', (c) => c.json({ status: 'ok' }));
export default app;name = "my-api"main = "src/index.ts"compatibility_date = "2024-12-01"
[vars]AUTHRIM_ISSUER = "https://auth.example.com"AUTHRIM_AUDIENCE = "https://api.example.com"Honoでのスコープ検証
import { createMiddleware } from 'hono/factory';
function requireScope(...scopes: string[]) { return createMiddleware(async (c, next) => { const auth = getAuth(c);
if (!auth) { return c.json({ error: 'unauthorized' }, 401); }
const tokenScopes = auth.scope?.split(' ') ?? []; const hasAll = scopes.every((s) => tokenScopes.includes(s));
if (!hasAll) { return c.json({ error: 'insufficient_scope', required: scopes, }, 403); }
await next(); });}
app.get('/api/admin', authrimMiddleware(server), requireScope('admin:read'), (c) => { return c.json({ admin: true });});Koaアダプター
@authrim/server/adapters/koa からインポートします。
Koaは認証データを ctx.state に格納します。
authrimMiddleware()
必須認証:
import Koa from 'koa';import Router from '@koa/router';import { createAuthrimServer } from '@authrim/server';import { authrimMiddleware } from '@authrim/server/adapters/koa';
const server = createAuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com',});
const app = new Koa();const router = new Router();
// Protect all API routesapp.use(authrimMiddleware(server));
router.get('/api/profile', (ctx) => { ctx.body = { sub: ctx.state.auth.sub, tokenType: ctx.state.authTokenType, };});
app.use(router.routes());app.listen(3000);authrimOptionalMiddleware()
オプション認証:
import { authrimOptionalMiddleware } from '@authrim/server/adapters/koa';
router.get('/api/feed', authrimOptionalMiddleware(server), (ctx) => { if (ctx.state.auth) { ctx.body = { feed: getPersonalizedFeed(ctx.state.auth.sub) }; } else { ctx.body = { feed: getPublicFeed() }; }});ステートプロパティ
| プロパティ | 型 | 説明 |
|---|---|---|
ctx.state.auth | ValidatedToken | undefined | 検証済みトークンのクレーム |
ctx.state.authTokenType | 'Bearer' | 'DPoP' | undefined | 使用されたトークンタイプ |
Koa完全サンプル
import Koa from 'koa';import Router from '@koa/router';import { createAuthrimServer } from '@authrim/server';import { authrimMiddleware, authrimOptionalMiddleware,} from '@authrim/server/adapters/koa';
const server = createAuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com',});
const app = new Koa();const router = new Router();
// Health check — no authrouter.get('/health', (ctx) => { ctx.body = { status: 'ok' };});
// Optional authrouter.get('/api/posts', authrimOptionalMiddleware(server), (ctx) => { const user = ctx.state.auth?.sub ?? 'anonymous'; ctx.body = { user, posts: getPosts(user) };});
// Protected routesconst protectedRouter = new Router({ prefix: '/api/me' });protectedRouter.use(authrimMiddleware(server));
protectedRouter.get('/profile', (ctx) => { ctx.body = { sub: ctx.state.auth.sub, email: ctx.state.auth.email };});
protectedRouter.get('/settings', (ctx) => { ctx.body = { settings: getUserSettings(ctx.state.auth.sub) };});
app.use(router.routes());app.use(protectedRouter.routes());app.listen(3000);KoaのTypeScript型拡張
import type { ValidatedToken } from '@authrim/server';
declare module 'koa' { interface DefaultState { auth: ValidatedToken; authTokenType: 'Bearer' | 'DPoP'; }}NestJSアダプター
@authrim/server/adapters/nestjs からインポートします。
NestJSはルート保護に Guard を使用します。アダプターはNestJSの依存性注入システムと互換性のあるGuardクラスを生成するファクトリ関数を提供します。
createAuthrimGuard()
必須認証 — 無効なトークンに対して HttpException(401) をスローします:
import { Module, Controller, Get, UseGuards } from '@nestjs/common';import { HttpException } from '@nestjs/common';import { createAuthrimServer } from '@authrim/server';import { createAuthrimGuard, getAuthFromRequest, getAuthTokenTypeFromRequest,} from '@authrim/server/adapters/nestjs';
const server = createAuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com',});
const AuthGuard = createAuthrimGuard(server, HttpException);
@Controller('api')@UseGuards(AuthGuard)export class ApiController { @Get('profile') getProfile(@Req() req: Request) { const auth = getAuthFromRequest(req); const tokenType = getAuthTokenTypeFromRequest(req);
return { sub: auth?.sub, tokenType }; }}createAuthrimOptionalGuard()
オプション認証 — 未認証のリクエストを拒否しません:
import { createAuthrimOptionalGuard } from '@authrim/server/adapters/nestjs';
const OptionalAuthGuard = createAuthrimOptionalGuard(server);
@Controller('public')@UseGuards(OptionalAuthGuard)export class PublicController { @Get('feed') getFeed(@Req() req: Request) { const auth = getAuthFromRequest(req); if (auth) { return { feed: getPersonalizedFeed(auth.sub) }; } return { feed: getPublicFeed() }; }}ヘルパー関数
| 関数 | 戻り値の型 | 説明 |
|---|---|---|
getAuthFromRequest(context) | ValidatedToken | undefined | ExecutionContext または Request から認証情報を取得 |
getAuthTokenTypeFromRequest(context) | 'Bearer' | 'DPoP' | undefined | トークンタイプを取得 |
カスタム @Auth() パラメータデコレーター
よりクリーンなコントローラーコードのための便利なパラメータデコレーターを作成します:
import { createParamDecorator, ExecutionContext } from '@nestjs/common';import { getAuthFromRequest } from '@authrim/server/adapters/nestjs';import type { ValidatedToken } from '@authrim/server';
export const Auth = createParamDecorator( (data: unknown, ctx: ExecutionContext): ValidatedToken | undefined => { const request = ctx.switchToHttp().getRequest(); return getAuthFromRequest(request); },);コントローラーでの使用方法:
@Controller('api')@UseGuards(AuthGuard)export class ApiController { @Get('profile') getProfile(@Auth() auth: ValidatedToken) { return { sub: auth.sub, email: auth.email }; }}NestJS完全サンプル
import { Module, Global } from '@nestjs/common';import { HttpException } from '@nestjs/common';import { createAuthrimServer } from '@authrim/server';import { createAuthrimGuard, createAuthrimOptionalGuard } from '@authrim/server/adapters/nestjs';
const server = createAuthrimServer({ issuer: process.env.AUTHRIM_ISSUER!, audience: process.env.AUTHRIM_AUDIENCE!,});
export const AuthGuard = createAuthrimGuard(server, HttpException, { realm: 'my-api', onError: (err) => console.warn('Auth error:', err.code),});
export const OptionalAuthGuard = createAuthrimOptionalGuard(server);
@Global()@Module({})export class AuthModule {}import { Controller, Get, UseGuards } from '@nestjs/common';import { AuthGuard, OptionalAuthGuard } from './auth.module';import { Auth } from './auth.decorator';import type { ValidatedToken } from '@authrim/server';
@Controller('users')export class UsersController { @Get('me') @UseGuards(AuthGuard) getMe(@Auth() auth: ValidatedToken) { return { sub: auth.sub, email: auth.email }; }
@Get() @UseGuards(OptionalAuthGuard) listUsers(@Auth() auth: ValidatedToken | undefined) { if (auth) { return { users: getAllUsers(), requestedBy: auth.sub }; } return { users: getPublicUsers() }; }}フレームワーク比較
| 項目 | Express | Fastify | Hono | Koa | NestJS |
|---|---|---|---|---|---|
| 認証情報の場所 | req.auth | request.auth | getAuth(c) | ctx.state.auth | getAuthFromRequest(req) |
| 必須ミドルウェア | authrimMiddleware() | authrimPreHandler() | authrimMiddleware() | authrimMiddleware() | createAuthrimGuard() |
| オプションミドルウェア | authrimOptionalMiddleware() | authrimOptionalPreHandler() | authrimOptionalMiddleware() | authrimOptionalMiddleware() | createAuthrimOptionalGuard() |
| アプリ全体の適用 | app.use(...) | authrimPlugin() | app.use(path, ...) | app.use(...) | コントローラーに @UseGuards() |
| 型安全性 | declare global | declare module | コンテキスト変数 | declare module | パラメータデコレーター |
次のステップ
- Express & Fastifyアダプター — ExpressとFastifyの統合詳細
- エラーハンドリング — エラーコードとレスポンスユーティリティ
- 設定リファレンス — サーバー設定オプション