Files
Latte 6b9c550d10
CI / lint (pull_request) Successful in 51s
CI / test (pull_request) Successful in 58s
docker / lint (pull_request) Successful in 49s
CI / publish (pull_request) Has been skipped
docker / test (pull_request) Successful in 59s
docker / docker (pull_request) Successful in 1m10s
docs: document using Gitea as the OAuth issuer
familiar is issuer-agnostic (resource server only), so Gitea can back
oauth mode with config alone: RS256 JWTs, JWKS at /login/oauth/keys, and
OIDC discovery. Add a deployment.md section covering the env config, the
aud=client-ID audience pitfall, and the no-DCR caveat; add a Gitea block
to .env.example; and note in claude-web.md that Gitea can't back the
claude.ai web connector (which requires DCR).
2026-07-12 17:52:26 +02:00

2.8 KiB

Connect Claude web (claude.ai)

Auth: OAuth 2.1 only. Prereq: familiar in oauth mode behind HTTPS, plus an external identity provider.

The claude.ai custom-connector flow speaks OAuth 2.1 with Dynamic Client Registration (DCR) and does not accept a static bearer token. familiar itself is only a resource server — it validates JWTs and advertises where to authenticate, but it is not an authorization server and does no DCR. So Claude web needs an external IdP that supports DCR (e.g. Authentik or Keycloak) sitting in front.

Gitea won't work here. Gitea is a fine OAuth issuer for familiar in general (see deployment.md → Using Gitea as the OAuth issuer), but it has no Dynamic Client Registration, which this connector requires. Use it only with clients that take a pre-registered client ID/secret, or put a DCR-capable IdP in front.

Simpler alternative: if you don't want to run an IdP, use the Claude Desktop app with a bearer token instead — see Connect Claude Desktop. Bearer is easier for every client except the claude.ai web connector.

1. Set up the IdP (external)

On your IdP, create an application/provider for familiar that:

  • issues JWT access tokens signed with a key published at a JWKS endpoint,
  • sets the token audience to familiar's public URL (the resource),
  • supports Dynamic Client Registration so claude.ai can register itself.

Note the issuer URL and (optionally) the JWKS URL.

2. Configure familiar in oauth mode

FAMILIAR_AUTH_MODE=oauth
FAMILIAR_OAUTH_ISSUER=https://idp.yourdomain.tld/application/o/familiar/
FAMILIAR_OAUTH_RESOURCE=https://familiar.yourdomain.tld
# FAMILIAR_OAUTH_AUDIENCE defaults to the resource URL; override if your IdP differs.
# FAMILIAR_OAUTH_JWKS_URI is discovered from the issuer's OIDC metadata if unset.

No FAMILIAR_HTTP_TOKEN is needed in oauth mode. familiar serves the discovery document at https://familiar.yourdomain.tld/.well-known/oauth-protected-resource/mcp, and unauthenticated MCP calls return 401 with a WWW-Authenticate: Bearer header pointing at your issuer.

3. Add the connector

In claude.ai: Settings → Connectors → Add custom connector, URL https://familiar.yourdomain.tld/mcp. Claude discovers your IdP from the metadata, registers via DCR, and runs the OAuth login. Approve familiar's scopes and you're connected.

Troubleshooting

  • "couldn't connect" immediately — familiar isn't in oauth mode, or FAMILIAR_OAUTH_RESOURCE/ISSUER are unset; the metadata endpoint must return 200.
  • Login loops / invalid token — audience mismatch: your IdP's token aud must equal FAMILIAR_OAUTH_RESOURCE (or your FAMILIAR_OAUTH_AUDIENCE).
  • DCR fails — the IdP doesn't have Dynamic Client Registration enabled; claude.ai requires it.