@blakearoberts/visage

中文文档
0.0.6发布于 2026/11/15MITTypeScriptES Module构建来源已验证近 30 天下载 4101

Vite plugin for local development with HMR and OIDC session cookie lifecycle semantics.

原始使用文档
文档目录12 节
  1. Getting Started
  2. Why Visage
  3. System Block Diagram
  4. Configuration
  5. Services
  6. Remotes
  7. External IdPs
  8. Telemetry
  9. Required Tools
  10. Managed Docker Images
  11. Security Notes
  12. Troubleshooting

Visage

Visage (/vit·ɛdʒ/) is a Vite plugin for local development with HMR and OIDC session cookie lifecycle semantics.

Getting Started

Install Visage from npm:

npm install @blakearoberts/visage@next

Add the plugin to vite.config.ts:

import { defineConfig } from 'vite';
import visage from '@blakearoberts/visage';

export default defineConfig({
  plugins: [visage()],
});

Start Vite normally:

vite

By default, you can reach the app at https://localhost:9001. You will be redirected to Dex to sign in. The default username and password is [email protected] and pass.

Why Visage

Visage is a local development harness for web apps that run behind an auth-protected edge, where browser sessions are represented by secure cookies backed by OIDC tokens.

Visage narrows the gap between local development, automated tests, and production by bringing production-like session lifecycle semantics to local Vite development without giving up HMR. That makes it practical to iterate on SSR identity injection, session timeout recovery, lock screens, and authenticated API calls.

Visage can also use a hosted IdP, so local frontend code can call hosted backend APIs with real credentials. That avoids frontend-only auth mocks or backend-only local bypasses: code can be written for production and still work locally.

System Block Diagram

flowchart LR
  browser([Browser])
  vite([Vite])
  upstreams([Upstreams])

  subgraph docker[Docker]
    nginx[NGINX]
    services([Services])
    Oauth2-Proxy
    idp(["IdP (Dex)"])

    nginx -.-> idp
    nginx -.-> Oauth2-Proxy -.-> idp
    nginx --> services
  end

  browser --> nginx
  nginx --> vite
  nginx ---> upstreams

Configuration

Visage is configured through visage(options?) in vite.config.ts.

The top-level host and port configure the local Visage origin that the browser visits:

visage({ host: 'localhost', port: 9001 });

Services

Services are Docker Compose services managed by the Vite dev-server lifecycle. Services automatically create upstream locations on the app host at /{name} which Visage removes before proxying the request to the service host.

visage({
  services: { whoami: { image: 'traefik/whoami' } },
});

Service Networks

Each service joins its own private Docker network. NGINX joins the private networks of services with upstreams. To allow direct service-to-service connections, add the same network name to each service's networks list.

visage({
  services: {
    api: { image: 'example/api' },
    res: { image: 'mysql', upstream: false, networks: ['api'] },
  },
});

Remotes

Remotes are upstreams without a Visage managed Docker container process. Remotes automatically create upstream locations on the app host behind at /{name} which Visage removes before proxying the request to the upstream host.

visage({
  remotes: {
    api: { host: 'api.remote.test' },
  },
});

Service and remote locations do not forward bearer tokens by default. Set auth.forward to true to forward the default bearer token for the upstream kind: remotes receive the OAuth access token, while services receive the OIDC ID token.

Hosted backend APIs that validate bearer auth should generally receive the access token, provided the token is issued for that API's issuer, audience, and scopes. Use 'access' or 'id' when you need to force a specific token kind.

visage({
  remotes: {
    api: {
      host: 'api.remote.test',
      auth: { forward: true },
    },
  },
});

OAuth2 Proxy can also return X-Auth-Request-Groups and X-Auth-Request-Preferred-Username, but Visage does not capture or forward them automatically. Capture and forward optional identity values as needed:

visage({
  remotes: {
    api: {
      directives: {
        auth_request_set: [
          '$auth_groups $upstream_http_x_auth_request_groups',
          '$auth_preferred_username $upstream_http_x_auth_request_preferred_username',
        ],
      },
      headers: {
        'X-Auth-Request-Groups': '$auth_groups',
        'X-Auth-Request-Preferred-Username': '$auth_preferred_username',
      },
    },
  },
});

Authenticated locations also get CSRF checks by default. Set csrf: false when the upstream intentionally handles cross-site browser requests itself. See CSRF Policy.

External IdPs

The default IdP, Dex, can be replaced with an external OIDC provider:

visage({
  idp: { issuer: 'https://idp.example.test/oauth2/default' },
});

Configure authorization, token, or jwks only when the provider endpoints must be rendered explicitly instead of discovered from the issuer. Configure end_session_endpoint when the provider supports OIDC end-session redirects.

Visage delegates principal admission to the identity provider and configures OAuth2 Proxy to accept any non-empty email asserted by that issuer. With managed Dex, idp.users is the complete eligible user list. With an external IdP, its client registration and application-assignment policy must ensure every identity that can obtain an OIDC response for the Visage client is intended to access the local application; Visage does not apply an additional email-domain allowlist.

Telemetry

Set telemetry to enable collection, redaction, and export of telemetry signals via OTLP/gRPC.

  • When enabled, Visage configures:

    • NGINX to export access spans to the Collector;
    • OAuth2 Proxy Prometheus metrics listener to be scraped by the Collector;
    • Service containers to send stdout/stderr to the Collector;
    • The Collector to accept authenticated OTLP/HTTP signals at /t/.
  • The Collector exports OTLP to host.docker.internal:4317 by default; the telemetry example demonstrates how to configure Grafana as a Visage managed service to receive and view the telemetry.

See VisageOptions for the full option surface.

Required Tools

  • Docker with Compose v2 support through docker compose.
  • mkcert installed on PATH, or configured with VISAGE_MKCERT=/path/to/mkcert.

Managed Docker Images

Visage pulls these as needed based on configuration:

ServiceImage
NGINXvisage-nginx
OAuth2 Proxyquay.io/oauth2-proxy/oauth2-proxy
Dexghcr.io/dexidp/dex
OpenTelemetry Collectorotel/opentelemetry-collector-contrib
Socatalpine/socat

The image tags Visage uses by default are defined by the manifest file, docker-compose.images.yml.

Security Notes

Visage is local-development tooling. It starts local auth infrastructure, terminates local HTTPS, and forwards authenticated identity or token material to configured upstreams.

Please report suspected vulnerabilities through GitHub private vulnerability reporting as described in Security Policy.

Do not treat the managed Dex and OAuth2 Proxy defaults as production auth infrastructure.

Visage's CSRF policy is the edge CSRF control for cookie-backed locations. Application CSRF tokens are not required for ordinary same-origin SPA mutations under this policy. App-level tokens may still be useful when a location disables the edge policy, intentionally accepts cross-site browser requests, or needs a token that encodes additional authorization semantics. CSP, frame-ancestors, and other click-jacking controls remain application policy.

Troubleshooting

  • If startup fails immediately, confirm Docker is running and docker compose works.
  • If NGINX cannot start, check whether the configured port is already in use.
  • If the hostname cannot be resolved, Visage may need permission to update /etc/hosts.

版本与发布记录

@blakearoberts/visage 共发布 158 个版本,首次发布于 2026/05/11;过去 12 个月发布了 158 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.0.6latest2026/11/15今天
0.0.6-rc.31next2026/11/14今天
0.0.6-rc.302026/11/131 天前
0.0.6-rc.292026/11/131 天前
0.0.6-rc.282026/11/122 天前
0.0.6-rc.272026/11/122 天前

关于 @blakearoberts/visage 的常见问题

@blakearoberts/visage 是什么?

Vite plugin for local development with HMR and OIDC session cookie lifecycle semantics.

如何安装 @blakearoberts/visage?

在项目目录运行 npm install @blakearoberts/visage,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:vite(^8.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@blakearoberts/visage 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@blakearoberts/visage 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@blakearoberts/visage 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@blakearoberts/visage 可以商用吗?

@blakearoberts/visage 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@blakearoberts/visage 的下载量有多少?

根据 npm 官方下载统计,@blakearoberts/visage 在 2026/10/09 – 2026/11/07 这 30 天内被下载 4,101 次,日均约 137 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@blakearoberts/visage 还在维护吗?

最新版本 0.0.6 发布于 2026/11/15(今天);至今共发布 158 个版本,其中过去 12 个月发布了 158 个;首次发布于 2026/05/11。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。