@o3co/create-auth-provider 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.ja.md +107 -0
  2. package/README.md +107 -0
  3. package/dist/__tests__/index.test.d.mts +2 -0
  4. package/dist/__tests__/index.test.d.mts.map +1 -0
  5. package/dist/__tests__/index.test.mjs +226 -0
  6. package/dist/cli.d.mts +3 -0
  7. package/dist/cli.d.mts.map +1 -0
  8. package/dist/cli.mjs +18 -0
  9. package/dist/index.d.mts +5 -0
  10. package/dist/index.d.mts.map +1 -0
  11. package/dist/index.mjs +166 -0
  12. package/package.json +28 -0
  13. package/templates/standalone/.dockerignore +9 -0
  14. package/templates/standalone/.env.example +21 -0
  15. package/templates/standalone/Dockerfile +58 -0
  16. package/templates/standalone/Makefile +12 -0
  17. package/templates/standalone/README.ja.md +205 -0
  18. package/templates/standalone/README.md +205 -0
  19. package/templates/standalone/config/application.conf +132 -0
  20. package/templates/standalone/config/clients.yaml +2 -0
  21. package/templates/standalone/config/clients.yaml.example +14 -0
  22. package/templates/standalone/config/development.conf +8 -0
  23. package/templates/standalone/config/production.conf +10 -0
  24. package/templates/standalone/docker-compose.test.yml +16 -0
  25. package/templates/standalone/docker-compose.yml +26 -0
  26. package/templates/standalone/package.json +45 -0
  27. package/templates/standalone/src/__tests__/configPath.test.mts +50 -0
  28. package/templates/standalone/src/__tests__/smoke.test.mts +204 -0
  29. package/templates/standalone/src/app.mts +201 -0
  30. package/templates/standalone/src/configPath.mts +37 -0
  31. package/templates/standalone/src/logger.mts +18 -0
  32. package/templates/standalone/tests/Makefile +5 -0
  33. package/templates/standalone/tests/did-grant.test.js +193 -0
  34. package/templates/standalone/tests/index.test.js +218 -0
  35. package/templates/standalone/tests/package-lock.json +2225 -0
  36. package/templates/standalone/tests/package.json +17 -0
  37. package/templates/standalone/tsconfig.json +12 -0
  38. package/templates/standalone/vitest.config.mts +7 -0
  39. package/templates/versions.json +9 -0
@@ -0,0 +1,9 @@
1
+ node_modules
2
+ dist
3
+ .git
4
+ .gitignore
5
+ .env*
6
+ !.env.example
7
+ *.md
8
+ docker-compose*.yml
9
+ Makefile
@@ -0,0 +1,21 @@
1
+ # Required
2
+ OAUTH_JWT_SECRET=
3
+ SESSION_SECRET=
4
+
5
+ # User repository
6
+ CLIENT_USER_AUTHENTICATE_URL=
7
+ CLIENT_USER_AUTHENTICATE_BY_TOKEN_URL=
8
+
9
+ # Redis (code repository + session storage)
10
+ # Use redis://redis:6379 when running via docker compose
11
+ CLIENT_CODE_ENDPOINT_URI=redis://redis:6379
12
+ SESSION_STORAGE_REDIS_URL=redis://redis:6379
13
+
14
+ # Development (override for local HTTP)
15
+ SESSION_SECURE=false
16
+
17
+ # Optional
18
+ # HTTP_PORT=3000
19
+ # OAUTH_JWT_ISSUER=
20
+ # OAUTH_ACCESS_TOKEN_EXPIRES_IN=3600
21
+ # OAUTH_REFRESH_TOKEN_EXPIRES_IN=86400
@@ -0,0 +1,58 @@
1
+ FROM node:24-alpine AS node-base
2
+
3
+ ENV HOME=/home/node
4
+
5
+ RUN apk add --no-cache tini \
6
+ && npm install -g corepack --force \
7
+ && corepack enable
8
+
9
+ WORKDIR /home/node
10
+
11
+ #############################################
12
+ FROM node-base AS deps
13
+
14
+ COPY package.json ./
15
+
16
+ RUN pnpm install
17
+
18
+ #############################################
19
+ FROM deps AS builder
20
+
21
+ COPY tsconfig.json ./
22
+ COPY config/ ./config/
23
+ COPY src/ ./src/
24
+
25
+ RUN pnpm run build
26
+
27
+ #############################################
28
+ FROM node-base AS runtime
29
+
30
+ ENV NODE_ENV=production
31
+
32
+ COPY --from=deps /home/node/package.json /home/node/pnpm-lock.yaml ./
33
+
34
+ RUN pnpm install --prod \
35
+ && pnpm store prune
36
+
37
+ COPY --from=builder /home/node/dist/ ./dist/
38
+ COPY --from=builder /home/node/config/ ./config/
39
+
40
+ USER node
41
+
42
+ ENTRYPOINT ["tini", "--"]
43
+ CMD ["node", "dist/app.mjs"]
44
+
45
+ #############################################
46
+ FROM builder AS test
47
+
48
+ COPY vitest.config.mts ./
49
+ COPY tests/ ./tests/
50
+
51
+ CMD ["pnpm", "run", "test", "--", "--passWithNoTests"]
52
+
53
+ #############################################
54
+ FROM builder AS develop
55
+
56
+ USER node
57
+
58
+ CMD ["pnpm", "run", "debug"]
@@ -0,0 +1,12 @@
1
+ IMAGE ?= auth-provider
2
+
3
+ .PHONY: dev test build
4
+
5
+ dev:
6
+ docker compose up --build
7
+
8
+ test:
9
+ docker compose -f docker-compose.test.yml up --build --abort-on-container-exit --exit-code-from test
10
+
11
+ build:
12
+ docker build --target runtime -t $(IMAGE) .
@@ -0,0 +1,205 @@
1
+ # @o3co/auth-provider-standalone
2
+
3
+ auth.provider のデプロイ可能なサーバーテンプレートです。これは composition root であり、設定を読み込み、モジュールをロードし、Express サーバーを起動します。`@o3co/create-auth-provider` で生成されます。
4
+
5
+ ## 使い方
6
+
7
+ ```bash
8
+ # 依存関係をインストール
9
+ pnpm install
10
+
11
+ # 環境変数ファイルをコピーして必須値を記入
12
+ cp .env.example .env
13
+
14
+ # 開発モードで起動(ホットリロード)
15
+ pnpm run debug
16
+
17
+ # ビルドして本番モードで起動
18
+ pnpm run build
19
+ pnpm start
20
+ ```
21
+
22
+ ## 設定
23
+
24
+ 設定は `config/application.conf`(HOCON 形式)から読み込まれます。各値は対応する環境変数で上書きできます。
25
+
26
+ ### 環境別コンフィグ overlay
27
+
28
+ `src/app.mts` は 2 層構成でコンフィグを読み込みます:
29
+
30
+ 1. **`config/application.conf`** — アプリの基本デフォルト。
31
+ 2. **`config/{ENV}.conf`** — 現在の環境の overlay。
32
+ `ENV = CONFIG_ENV || NODE_ENV || "development"` で決まります。
33
+
34
+ overlay の値は `application.conf` を上書きします。scaffold には
35
+ `development.conf` と `production.conf` が同梱されています。別の環境
36
+ (例: `staging`)を追加するときは `config/staging.conf` を作成し、
37
+ `CONFIG_ENV=staging` を設定してください。`{ENV}.conf` が存在しない場合は
38
+ 起動時にエラーになります(タイポを silent に素通りさせず fail-fast します)。
39
+
40
+ ### HTTP
41
+
42
+ | 変数 | デフォルト | 説明 |
43
+ |---|---|---|
44
+ | `HTTP_PORT` | `3000` | サーバーがリッスンするポート |
45
+ | `HTTP_TRUST_PROXY` | `false` | リバースプロキシの背後で動作する場合は `true` に設定 |
46
+
47
+ ### OAuth JWT
48
+
49
+ | 変数 | デフォルト | 説明 |
50
+ |---|---|---|
51
+ | `OAUTH_JWT_ALGORITHM` | `HS256` | JWT 署名アルゴリズム(例: `RS256`、`ES256`) |
52
+ | `OAUTH_JWT_SECRET` | — | 署名シークレット(HMAC アルゴリズム用) |
53
+ | `OAUTH_JWT_ISSUER` | — | JWT の `iss` クレーム値 |
54
+ | `OAUTH_JWT_KID` | `v0` | JWT ヘッダーに含まれる key ID |
55
+ | `OAUTH_JWT_PRIVATE_KEY` | — | PEM エンコードされた秘密鍵(非対称アルゴリズム用) |
56
+ | `OAUTH_JWT_PRIVATE_KEY_PATH` | — | PEM 秘密鍵ファイルのパス |
57
+ | `OAUTH_JWT_PUBLIC_KEY` | — | PEM エンコードされた公開鍵 |
58
+ | `OAUTH_JWT_PUBLIC_KEY_PATH` | — | PEM 公開鍵ファイルのパス |
59
+
60
+ ### トークン有効期限
61
+
62
+ | 変数 | デフォルト | 説明 |
63
+ |---|---|---|
64
+ | `OAUTH_ACCESS_TOKEN_EXPIRES_IN` | `3600` | アクセストークンの有効期間(秒) |
65
+ | `OAUTH_REFRESH_TOKEN_EXPIRES_IN` | `86400` | リフレッシュトークンの有効期間(秒) |
66
+
67
+ ### グラントタイプ
68
+
69
+ | 変数 | デフォルト | 説明 |
70
+ |---|---|---|
71
+ | `OAUTH_GRANTS_SESSION_ENABLED` | `true` | session グラントタイプを有効化 |
72
+ | `OAUTH_GRANTS_AUTHORIZATION_ENABLED` | `true` | authorization code グラントタイプを有効化 |
73
+ | `OAUTH_GRANTS_REFRESH_TOKEN_ENABLED` | `true` | refresh token グラントタイプを有効化 |
74
+
75
+ ### Session
76
+
77
+ | 変数 | デフォルト | 説明 |
78
+ |---|---|---|
79
+ | `SESSION_SECRET` | — | **必須。** セッション署名シークレット |
80
+ | `SESSION_MAX_AGE` | `3600000` | セッション Cookie の最大有効期間(ミリ秒) |
81
+ | `SESSION_SECURE` | `true` | セッション Cookie に `Secure` フラグを設定 |
82
+ | `SESSION_SAME_SITE` | `lax` | `SameSite` 属性(`lax`、`strict`、`none`) |
83
+ | `SESSION_DOMAIN` | — | Cookie ドメイン(デフォルト未設定) |
84
+ | `SESSION_STORAGE_TYPE` | `redis` | セッションストアのバックエンド: `redis` または `memory` |
85
+ | `SESSION_STORAGE_REDIS_URL` | `redis://localhost:6379` | セッションストア用 Redis 接続 URL |
86
+ | `SESSION_STORAGE_REDIS_PASSWORD` | — | セッションストア用 Redis パスワード |
87
+
88
+ ### Google フェデレーション
89
+
90
+ | 変数 | デフォルト | 説明 |
91
+ |---|---|---|
92
+ | `FEDERATIONS_GOOGLE_ENABLED` | `false` | Google OAuth フェデレーションを有効化 |
93
+ | `FEDERATIONS_GOOGLE_CLIENT_ID` | — | Google OAuth クライアント ID |
94
+ | `FEDERATIONS_GOOGLE_CLIENT_SECRET` | — | Google OAuth クライアントシークレット |
95
+ | `FEDERATIONS_GOOGLE_CALLBACK_URL` | `http://localhost:3000/session/oauth/federation/google/callback` | Google OAuth コールバック URL |
96
+
97
+ ### クライアントリポジトリ
98
+
99
+ | 変数 | デフォルト | 説明 |
100
+ |---|---|---|
101
+ | `CLIENT_TYPE` | `yaml` | クライアントストアのバックエンド: `yaml` |
102
+ | `CLIENT_PATH` | `./config/clients.yaml` | YAML クライアントレジストリのパス |
103
+
104
+ ### ユーザーリポジトリ
105
+
106
+ | 変数 | デフォルト | 説明 |
107
+ |---|---|---|
108
+ | `CLIENT_USER_TYPE` | `http` | ユーザーリポジトリのバックエンド: `http` |
109
+ | `CLIENT_USER_AUTHENTICATE_URL` | — | パスワード認証用のユーザー認証 URL |
110
+ | `CLIENT_USER_AUTHENTICATE_BY_TOKEN_URL` | — | トークン認証用のユーザー認証 URL |
111
+ | `CLIENT_USER_TIMEOUT` | `5000` | HTTP リクエストタイムアウト(ミリ秒) |
112
+
113
+ ### コードリポジトリ
114
+
115
+ | 変数 | デフォルト | 説明 |
116
+ |---|---|---|
117
+ | `CLIENT_CODE_TYPE` | `redis` | 認可コードストアのバックエンド: `redis` |
118
+ | `CLIENT_CODE_ENDPOINT_URI` | — | コードストア用 Redis 接続 URI |
119
+ | `CLIENT_CODE_PASSWORD` | — | コードストア用 Redis パスワード |
120
+ | `CLIENT_CODE_DEFAULT_EXPIRES_IN` | `600` | 認可コードのデフォルト有効期間(秒) |
121
+
122
+ ### エンドポイント
123
+
124
+ | 変数 | デフォルト | 説明 |
125
+ |---|---|---|
126
+ | `ENDPOINTS_LOGIN_URL` | — | ログインページの URL(リダイレクト先) |
127
+ | `ENDPOINTS_CLIENT_URL` | — | クライアントアプリケーションの URL |
128
+ | `ENDPOINTS_AUTH_CALLBACK_URL` | — | 認可コールバックの URL |
129
+
130
+ ## モジュール合成順序
131
+
132
+ モジュールは以下の順序で登録されます。各モジュールは独自のルートとグラントタイプを登録します。
133
+
134
+ 1. **`oauthModule`** — OAuth 2.0 コアエンドポイント: `POST /oauth/token`、`POST /oauth/introspect`、`GET /oauth/authorize`
135
+ 2. **`sessionModule`** — セッションベースのログイン・ログアウトおよびフェデレーション: `POST /session/login`、`POST /session/logout`、`GET/POST /session/oauth/federation/*`
136
+ 3. **`oauthSessionModule`** — session グラントタイプ(有効なセッションをトークンに交換)
137
+ 4. **`oauthAuthorizationModule`** — authorization code および refresh token グラントタイプ
138
+
139
+ ## 組み込みルート
140
+
141
+ 以下のルートはモジュールシステムの外部で登録されます。
142
+
143
+ | メソッド | パス | 説明 |
144
+ |---|---|---|
145
+ | `GET` | `/health` | ヘルスチェックエンドポイント |
146
+ | `GET` | `/.well-known/jwks.json` | トークン検証用公開鍵セット(JWKS) |
147
+
148
+ ## Docker
149
+
150
+ Dockerfile はマルチステージビルドを使用しており、以下のターゲットがあります。
151
+
152
+ | ターゲット | 用途 |
153
+ |---|---|
154
+ | `runtime` | 本番イメージ(コンパイル済み JS のみ) |
155
+ | `develop` | ホットリロード付き開発イメージ(`pnpm run debug`) |
156
+ | `test` | テストランナーイメージ |
157
+
158
+ ```bash
159
+ # 本番イメージをビルド
160
+ make build IMAGE=my-auth-provider
161
+
162
+ # docker compose で起動(開発用)
163
+ make dev
164
+
165
+ # Docker でテストを実行
166
+ make test
167
+ ```
168
+
169
+ `docker-compose.yml` は認証サーバーと Redis コンテナをまとめて起動します。環境変数は `.env` で設定してください。
170
+
171
+ ## カスタムモジュールの追加
172
+
173
+ カスタムモジュールを追加するには、`src/app.mts` でインポートし、`createApp` に渡す `modules` 配列に追加します。
174
+
175
+ ```typescript
176
+ import { myCustomModule } from "./modules/my-custom-module.mjs";
177
+
178
+ const { init, router, grantRegistry } = createApp(express, {
179
+ // ...
180
+ modules: [
181
+ oauthModule({ clientRepository, codeRepository, express }),
182
+ sessionModule({ userRepository, express }),
183
+ oauthSessionModule({ clientRepository }),
184
+ oauthAuthorizationModule({ codeRepository }),
185
+ myCustomModule, // ここに追加
186
+ ],
187
+ });
188
+ ```
189
+
190
+ ## npm スクリプト
191
+
192
+ | スクリプト | 説明 |
193
+ |---|---|
194
+ | `pnpm run build` | TypeScript を `dist/` にコンパイル |
195
+ | `pnpm start` | コンパイル済みサーバーを起動 |
196
+ | `pnpm run debug` | `tsx watch` でホットリロード起動(開発モード) |
197
+ | `pnpm test` | Vitest でテストを実行 |
198
+
199
+ ## 関連
200
+
201
+ - [`@o3co/auth-provider-core`](../../packages/core) — アプリケーションファクトリと設定スキーマ
202
+ - [`@o3co/auth-provider-oauth`](../../packages/oauth) — OAuth モジュール
203
+ - [`@o3co/auth-provider-session`](../../packages/session) — Session モジュール
204
+ - [`@o3co/auth-provider-foundation`](../../packages/foundation) — 組み込みアダプター登録
205
+ - [`@o3co/create-auth-provider`](../../create-app) — このテンプレートを生成する CLI スキャフォルダー
@@ -0,0 +1,205 @@
1
+ # @o3co/auth-provider-standalone
2
+
3
+ Deployable server template for auth.provider. This is the composition root — it reads config, loads modules, and starts the Express server. Generated by `@o3co/create-auth-provider`.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ pnpm install
10
+
11
+ # Copy environment file and fill in required values
12
+ cp .env.example .env
13
+
14
+ # Start in development mode (hot reload)
15
+ pnpm run debug
16
+
17
+ # Build and start in production mode
18
+ pnpm run build
19
+ pnpm start
20
+ ```
21
+
22
+ ## Configuration
23
+
24
+ Configuration is loaded from `config/application.conf` (HOCON format). Each value can be overridden with the corresponding environment variable.
25
+
26
+ ### Environment-specific config overlay
27
+
28
+ `src/app.mts` loads configuration in two layers:
29
+
30
+ 1. **`config/application.conf`** — base defaults for the app.
31
+ 2. **`config/{ENV}.conf`** — overlay for the current environment, where
32
+ `ENV = CONFIG_ENV || NODE_ENV || "development"`.
33
+
34
+ Values in the overlay take precedence over `application.conf`. The scaffold
35
+ ships with `development.conf` and `production.conf`. To add another
36
+ environment (e.g. `staging`), create `config/staging.conf` and set
37
+ `CONFIG_ENV=staging`. A missing `{ENV}.conf` is a boot-time error — typos
38
+ fail fast rather than silently falling back to defaults.
39
+
40
+ ### HTTP
41
+
42
+ | Variable | Default | Description |
43
+ |---|---|---|
44
+ | `HTTP_PORT` | `3000` | Port the server listens on |
45
+ | `HTTP_TRUST_PROXY` | `false` | Set to `true` when running behind a reverse proxy |
46
+
47
+ ### OAuth JWT
48
+
49
+ | Variable | Default | Description |
50
+ |---|---|---|
51
+ | `OAUTH_JWT_ALGORITHM` | `HS256` | JWT signing algorithm (e.g. `RS256`, `ES256`) |
52
+ | `OAUTH_JWT_SECRET` | — | Signing secret (HMAC algorithms) |
53
+ | `OAUTH_JWT_ISSUER` | — | JWT `iss` claim value |
54
+ | `OAUTH_JWT_KID` | `v0` | Key ID included in the JWT header |
55
+ | `OAUTH_JWT_PRIVATE_KEY` | — | PEM-encoded private key (asymmetric algorithms) |
56
+ | `OAUTH_JWT_PRIVATE_KEY_PATH` | — | Path to PEM private key file |
57
+ | `OAUTH_JWT_PUBLIC_KEY` | — | PEM-encoded public key |
58
+ | `OAUTH_JWT_PUBLIC_KEY_PATH` | — | Path to PEM public key file |
59
+
60
+ ### Token Expiry
61
+
62
+ | Variable | Default | Description |
63
+ |---|---|---|
64
+ | `OAUTH_ACCESS_TOKEN_EXPIRES_IN` | `3600` | Access token lifetime in seconds |
65
+ | `OAUTH_REFRESH_TOKEN_EXPIRES_IN` | `86400` | Refresh token lifetime in seconds |
66
+
67
+ ### Grant Types
68
+
69
+ | Variable | Default | Description |
70
+ |---|---|---|
71
+ | `OAUTH_GRANTS_SESSION_ENABLED` | `true` | Enable the session grant type |
72
+ | `OAUTH_GRANTS_AUTHORIZATION_ENABLED` | `true` | Enable the authorization code grant type |
73
+ | `OAUTH_GRANTS_REFRESH_TOKEN_ENABLED` | `true` | Enable the refresh token grant type |
74
+
75
+ ### Session
76
+
77
+ | Variable | Default | Description |
78
+ |---|---|---|
79
+ | `SESSION_SECRET` | — | **Required.** Session signing secret |
80
+ | `SESSION_MAX_AGE` | `3600000` | Session cookie max age in milliseconds |
81
+ | `SESSION_SECURE` | `true` | Set `Secure` flag on session cookie |
82
+ | `SESSION_SAME_SITE` | `lax` | `SameSite` attribute (`lax`, `strict`, `none`) |
83
+ | `SESSION_DOMAIN` | — | Cookie domain (unset by default) |
84
+ | `SESSION_STORAGE_TYPE` | `redis` | Session store backend: `redis` or `memory` |
85
+ | `SESSION_STORAGE_REDIS_URL` | `redis://localhost:6379` | Redis connection URL for session storage |
86
+ | `SESSION_STORAGE_REDIS_PASSWORD` | — | Redis password for session storage |
87
+
88
+ ### Google Federation
89
+
90
+ | Variable | Default | Description |
91
+ |---|---|---|
92
+ | `FEDERATIONS_GOOGLE_ENABLED` | `false` | Enable Google OAuth federation |
93
+ | `FEDERATIONS_GOOGLE_CLIENT_ID` | — | Google OAuth client ID |
94
+ | `FEDERATIONS_GOOGLE_CLIENT_SECRET` | — | Google OAuth client secret |
95
+ | `FEDERATIONS_GOOGLE_CALLBACK_URL` | `http://localhost:3000/session/oauth/federation/google/callback` | Google OAuth callback URL |
96
+
97
+ ### Client Repository
98
+
99
+ | Variable | Default | Description |
100
+ |---|---|---|
101
+ | `CLIENT_TYPE` | `yaml` | Client store backend: `yaml` |
102
+ | `CLIENT_PATH` | `./config/clients.yaml` | Path to the YAML client registry |
103
+
104
+ ### User Repository
105
+
106
+ | Variable | Default | Description |
107
+ |---|---|---|
108
+ | `CLIENT_USER_TYPE` | `http` | User repository backend: `http` |
109
+ | `CLIENT_USER_AUTHENTICATE_URL` | — | URL for password-based user authentication |
110
+ | `CLIENT_USER_AUTHENTICATE_BY_TOKEN_URL` | — | URL for token-based user authentication |
111
+ | `CLIENT_USER_TIMEOUT` | `5000` | HTTP request timeout in milliseconds |
112
+
113
+ ### Code Repository
114
+
115
+ | Variable | Default | Description |
116
+ |---|---|---|
117
+ | `CLIENT_CODE_TYPE` | `redis` | Authorization code store backend: `redis` |
118
+ | `CLIENT_CODE_ENDPOINT_URI` | — | Redis connection URI for code storage |
119
+ | `CLIENT_CODE_PASSWORD` | — | Redis password for code storage |
120
+ | `CLIENT_CODE_DEFAULT_EXPIRES_IN` | `600` | Default authorization code lifetime in seconds |
121
+
122
+ ### Endpoints
123
+
124
+ | Variable | Default | Description |
125
+ |---|---|---|
126
+ | `ENDPOINTS_LOGIN_URL` | — | URL of the login page (for redirects) |
127
+ | `ENDPOINTS_CLIENT_URL` | — | URL of the client application |
128
+ | `ENDPOINTS_AUTH_CALLBACK_URL` | — | URL of the authorization callback |
129
+
130
+ ## Module Composition Order
131
+
132
+ Modules are registered in the following order. Each module registers its own routes and grant types.
133
+
134
+ 1. **`oauthModule`** — Core OAuth 2.0 endpoints: `POST /oauth/token`, `POST /oauth/introspect`, `GET /oauth/authorize`
135
+ 2. **`sessionModule`** — Session-based login/logout and federation: `POST /session/login`, `POST /session/logout`, `GET/POST /session/oauth/federation/*`
136
+ 3. **`oauthSessionModule`** — Session grant type (exchanges a valid session for a token)
137
+ 4. **`oauthAuthorizationModule`** — Authorization code and refresh token grant types
138
+
139
+ ## Built-in Routes
140
+
141
+ The following routes are registered outside of the module system:
142
+
143
+ | Method | Path | Description |
144
+ |---|---|---|
145
+ | `GET` | `/health` | Health check endpoint |
146
+ | `GET` | `/.well-known/jwks.json` | Public key set (JWKS) for token verification |
147
+
148
+ ## Docker
149
+
150
+ The Dockerfile uses multi-stage builds with the following targets:
151
+
152
+ | Target | Purpose |
153
+ |---|---|
154
+ | `runtime` | Production image (compiled JS only) |
155
+ | `develop` | Development image with hot reload (`pnpm run debug`) |
156
+ | `test` | Test runner image |
157
+
158
+ ```bash
159
+ # Build the production image
160
+ make build IMAGE=my-auth-provider
161
+
162
+ # Start with docker compose (development)
163
+ make dev
164
+
165
+ # Run tests in Docker
166
+ make test
167
+ ```
168
+
169
+ The `docker-compose.yml` starts the auth server together with a Redis container. Configure environment variables in `.env`.
170
+
171
+ ## Adding Custom Modules
172
+
173
+ To add a custom module, import it in `src/app.mts` and include it in the `modules` array passed to `createApp`:
174
+
175
+ ```typescript
176
+ import { myCustomModule } from "./modules/my-custom-module.mjs";
177
+
178
+ const { init, router, grantRegistry } = createApp(express, {
179
+ // ...
180
+ modules: [
181
+ oauthModule({ clientRepository, codeRepository, express }),
182
+ sessionModule({ userRepository, express }),
183
+ oauthSessionModule({ clientRepository }),
184
+ oauthAuthorizationModule({ codeRepository }),
185
+ myCustomModule, // add here
186
+ ],
187
+ });
188
+ ```
189
+
190
+ ## npm Scripts
191
+
192
+ | Script | Description |
193
+ |---|---|
194
+ | `pnpm run build` | Compile TypeScript to `dist/` |
195
+ | `pnpm start` | Start the compiled server |
196
+ | `pnpm run debug` | Start with hot reload via `tsx watch` (development mode) |
197
+ | `pnpm test` | Run tests with Vitest |
198
+
199
+ ## See Also
200
+
201
+ - [`@o3co/auth-provider-core`](../../packages/core) — Application factory and config schema
202
+ - [`@o3co/auth-provider-oauth`](../../packages/oauth) — OAuth module
203
+ - [`@o3co/auth-provider-session`](../../packages/session) — Session module
204
+ - [`@o3co/auth-provider-foundation`](../../packages/foundation) — Built-in adapter registration
205
+ - [`@o3co/create-auth-provider`](../../create-app) — CLI scaffolder that generates this template
@@ -0,0 +1,132 @@
1
+ http {
2
+ port = 3000
3
+ port = ${?HTTP_PORT}
4
+ trustProxy = false
5
+ trustProxy = ${?HTTP_TRUST_PROXY}
6
+ }
7
+
8
+ oauth {
9
+ jwt {
10
+ issuer = ${?OAUTH_JWT_ISSUER}
11
+ signingKey {
12
+ provider = "local"
13
+ provider = ${?OAUTH_JWT_SIGNING_KEY_PROVIDER}
14
+ local {
15
+ algorithm = "HS256"
16
+ algorithm = ${?OAUTH_JWT_ALGORITHM}
17
+ kid = "v0"
18
+ kid = ${?OAUTH_JWT_KID}
19
+ secret = ${?OAUTH_JWT_SECRET}
20
+ privateKey = ${?OAUTH_JWT_PRIVATE_KEY}
21
+ privateKeyPath = ${?OAUTH_JWT_PRIVATE_KEY_PATH}
22
+ publicKey = ${?OAUTH_JWT_PUBLIC_KEY}
23
+ publicKeyPath = ${?OAUTH_JWT_PUBLIC_KEY_PATH}
24
+ previousKeys = []
25
+ }
26
+ }
27
+ }
28
+ accessToken {
29
+ expiresIn = 3600
30
+ expiresIn = ${?OAUTH_ACCESS_TOKEN_EXPIRES_IN}
31
+ }
32
+ refreshToken {
33
+ expiresIn = 86400
34
+ expiresIn = ${?OAUTH_REFRESH_TOKEN_EXPIRES_IN}
35
+ }
36
+ grants {
37
+ session { enabled = true, enabled = ${?OAUTH_GRANTS_SESSION_ENABLED} }
38
+ authorization {
39
+ enabled = true
40
+ enabled = ${?OAUTH_GRANTS_AUTHORIZATION_ENABLED}
41
+ pkce {
42
+ requireS256 = false
43
+ requireS256 = ${?OAUTH_GRANTS_AUTHORIZATION_PKCE_REQUIRE_S256}
44
+ }
45
+ }
46
+ refresh_token { enabled = true, enabled = ${?OAUTH_GRANTS_REFRESH_TOKEN_ENABLED} }
47
+ }
48
+ }
49
+
50
+ session {
51
+ secret = ${?SESSION_SECRET}
52
+ maxAge = 3600000
53
+ maxAge = ${?SESSION_MAX_AGE}
54
+ secure = true
55
+ secure = ${?SESSION_SECURE}
56
+ sameSite = "lax"
57
+ sameSite = ${?SESSION_SAME_SITE}
58
+ domain = null
59
+ domain = ${?SESSION_DOMAIN}
60
+ storage {
61
+ type = "redis"
62
+ type = ${?SESSION_STORAGE_TYPE}
63
+ redis {
64
+ url = "redis://localhost:6379"
65
+ url = ${?SESSION_STORAGE_REDIS_URL}
66
+ password = ${?SESSION_STORAGE_REDIS_PASSWORD}
67
+ }
68
+ }
69
+ }
70
+
71
+ rateLimit {
72
+ login { windowMs = 900000, limit = 20 }
73
+ }
74
+
75
+ federations {
76
+ google {
77
+ enabled = false
78
+ enabled = ${?FEDERATIONS_GOOGLE_ENABLED}
79
+ clientId = ${?FEDERATIONS_GOOGLE_CLIENT_ID}
80
+ clientSecret = ${?FEDERATIONS_GOOGLE_CLIENT_SECRET}
81
+ callbackURL = "http://localhost:3000/session/oauth/federation/google/callback"
82
+ callbackURL = ${?FEDERATIONS_GOOGLE_CALLBACK_URL}
83
+ }
84
+ }
85
+
86
+ repositories {
87
+ client {
88
+ type = "yaml"
89
+ type = ${?CLIENT_TYPE}
90
+ yaml {
91
+ path = "./config/clients.yaml"
92
+ path = ${?CLIENT_PATH}
93
+ }
94
+ }
95
+ user {
96
+ type = "http"
97
+ type = ${?CLIENT_USER_TYPE}
98
+ yaml {
99
+ path = "./config/users.yaml"
100
+ }
101
+ http {
102
+ authenticateUrl = ${?CLIENT_USER_AUTHENTICATE_URL}
103
+ authenticateByTokenUrl = ${?CLIENT_USER_AUTHENTICATE_BY_TOKEN_URL}
104
+ timeout = 5000
105
+ timeout = ${?CLIENT_USER_TIMEOUT}
106
+ }
107
+ }
108
+ code {
109
+ type = "redis"
110
+ type = ${?CLIENT_CODE_TYPE}
111
+ memory {
112
+ defaultExpiresIn = 600
113
+ defaultExpiresIn = ${?CLIENT_CODE_DEFAULT_EXPIRES_IN}
114
+ }
115
+ redis {
116
+ defaultExpiresIn = 600
117
+ defaultExpiresIn = ${?CLIENT_CODE_DEFAULT_EXPIRES_IN}
118
+ endpointUri = ${?CLIENT_CODE_ENDPOINT_URI}
119
+ password = ${?CLIENT_CODE_PASSWORD}
120
+ }
121
+ }
122
+ }
123
+
124
+ endpoints {
125
+ login { url = ${?ENDPOINTS_LOGIN_URL} }
126
+ client { url = ${?ENDPOINTS_CLIENT_URL} }
127
+ authCallback { url = ${?ENDPOINTS_AUTH_CALLBACK_URL} }
128
+ }
129
+
130
+ cors {
131
+ allowedOrigins = []
132
+ }
@@ -0,0 +1,2 @@
1
+ # Client definitions loaded via loadYamlMap into InMemoryClientRepository.
2
+ # Add client entries here. See clients.yaml.example for format.
@@ -0,0 +1,14 @@
1
+ # Example client definitions loaded via loadYamlMap into InMemoryClientRepository.
2
+ # Copy this file to clients.yaml and customize for your deployment.
3
+ #
4
+ # Secret format:
5
+ # - Plain text: "my-secret"
6
+ # - Bcrypt hash: "$2b$10$..." (generate with: node -e "require('bcrypt').hash('secret',10).then(console.log)")
7
+
8
+ my-app:
9
+ clientSecret: "$2b$10$REPLACE_WITH_BCRYPT_HASH"
10
+ allowedRedirectUris:
11
+ - "http://localhost:3000/callback"
12
+ allowedScopes:
13
+ - "read"
14
+ - "write"
@@ -0,0 +1,8 @@
1
+ # Environment overlay for development.
2
+ # Loaded when CONFIG_ENV (or NODE_ENV) is "development" — the default.
3
+ # Values here override application.conf.
4
+ #
5
+ # Most values are controlled via environment variables (see ${?VAR}
6
+ # substitutions in application.conf). Override entries here only when
7
+ # you need a fixed development-specific value that cannot come from
8
+ # an environment variable.
@@ -0,0 +1,10 @@
1
+ # Environment overlay for production.
2
+ # Loaded when CONFIG_ENV (or NODE_ENV) is "production".
3
+ # Values here override application.conf.
4
+ #
5
+ # Most production-sensitive values (OAUTH_JWT_SECRET, SESSION_SECRET, REDIS URLs,
6
+ # federation client secrets, etc.) should be supplied via environment variables —
7
+ # see the ${?VAR} substitutions in application.conf.
8
+ #
9
+ # Override entries here only when a value must be fixed per-environment rather
10
+ # than per-deployment (e.g. feature flags turned on only in production).