npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@xenkai-inc/cf-access

v0.1.0

Published

Cloudflare Access JWT 検証共通モジュール(T0328/T0329 で共有)

Readme

@xenkai-inc/cf-access

Cloudflare Access JWT 検証共通モジュール。

llm.xenkai.jp(T0328)と将来の Xenkai SDK(T0329 等)で再利用する。

v0 unstable: SemVer に従うが、v1.0.0 まではマイナーバージョンで破壊的変更が入る可能性があります。

インストール

npm install @xenkai-inc/cf-access

認証不要(npmjs public package)。

機能

  • Cloudflare Access JWT の RS256 署名検証
  • JWKS のメモリキャッシュ(TTL 1h、key rotation 対応)
  • クレーム検証: aud / iss / exp / nbf(60秒 clock drift 許容)
  • 型付きエラー(AccessJwtError.code)で 401/403/500 の切り分けが可能
  • VerifiedUserEmail branded type による型安全なメール取得

使い方

extractVerifiedEmail — JWT 検証とメール取得を一括で行う(推奨)

import { extractVerifiedEmail, AccessJwtError } from '@xenkai-inc/cf-access';

// teamDomain と aud は必ず呼び出し側の env から渡すこと(ハードコード禁止)
try {
  const email = await extractVerifiedEmail(
    request.headers.get('Cf-Access-Jwt-Assertion') ?? '',
    env.CF_ACCESS_TEAM_DOMAIN,  // 例: "xenkai"
    env.CF_ACCESS_AUD,          // Cloudflare Zero Trust Dashboard の AUD tag
  );
  // email は VerifiedUserEmail(JWT 検証済み branded string)
  console.log(email); // "[email protected]"
} catch (err) {
  if (err instanceof AccessJwtError) {
    // err.code で 401/403/500 を切り分け
  }
}

シグネチャ:

async function extractVerifiedEmail(
  jwt: string,
  teamDomain: string,
  aud: string,
): Promise<VerifiedUserEmail>

verifyAccessJwt + extractEmail — ペイロード全体が必要な場合

import { verifyAccessJwt, extractEmail, AccessJwtError } from '@xenkai-inc/cf-access';

try {
  // JWT を検証して AccessJwtPayload を返す
  const payload = await verifyAccessJwt(
    request.headers.get('Cf-Access-Jwt-Assertion') ?? '',
    env.CF_ACCESS_TEAM_DOMAIN,
    env.CF_ACCESS_AUD,
  );

  // payload から email を取得(verifyAccessJwt で存在が保証されている)
  const email = extractEmail(payload);

  // payload には aud / iss / exp / iat / sub / policy_id 等が含まれる
  console.log(payload.policy_id);
} catch (err) {
  if (err instanceof AccessJwtError) {
    switch (err.code) {
      case 'JWT_MISSING':
      case 'JWT_EXPIRED':
      case 'JWT_NOT_YET_VALID':
        return new Response('Unauthorized', { status: 401 });
      case 'JWT_INVALID_SIGNATURE':
      case 'JWT_INVALID_AUD':
      case 'JWT_INVALID_ISS':
      case 'JWT_MALFORMED':
      case 'JWT_EMAIL_MISSING':
        return new Response('Forbidden', { status: 403 });
      case 'JWKS_FETCH_FAILED':
        return new Response('Internal Server Error', { status: 500 });
    }
  }
  throw err;
}

env の設定

teamDomainaud は必ず呼び出し側の環境変数から渡してください。ソースコードへのハードコードは禁止です。

| 変数名 | 内容 | 取得場所 | |--------|------|----------| | CF_ACCESS_TEAM_DOMAIN | Cloudflare Access team domain(例: xenkai) | Zero Trust → Settings → Custom Pages | | CF_ACCESS_AUD | Application AUD tag | Zero Trust → Access → Applications → 対象アプリ |

エラーコード

| コード | HTTP ステータス | 原因 | |--------|-----------------|------| | JWT_MISSING | 401 | JWT が未指定または空 | | JWT_EXPIRED | 401 | JWT 有効期限切れ(clock drift 60秒超) | | JWT_NOT_YET_VALID | 401 | nbf が未来(clock drift 60秒超) | | JWT_INVALID_SIGNATURE | 403 | 署名検証失敗 | | JWT_INVALID_AUD | 403 | aud 不一致 | | JWT_INVALID_ISS | 403 | iss 不一致 | | JWT_MALFORMED | 403 | JWT 形式不正 | | JWT_EMAIL_MISSING | 403 | payload に email クレームなし | | JWKS_FETCH_FAILED | 500 | JWKS フェッチ失敗 |

開発

# テスト実行
npm test -w packages/cf-access

# 型チェック
npm run typecheck -w packages/cf-access

# ビルド
npm run build -w packages/cf-access