No description
  • JavaScript 95.4%
  • Nunjucks 4.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Ricardo 904d2c58d6 fix: bind code exchange to the code's own claims
`codeValidator` read the client an authorization code was issued to from
`request.app.locals.client`, set during the authorization request. `app.locals`
is shared by every request an Express application handles, so it holds
whichever authorization request happened last on the server, not necessarily
the one that issued the code being redeemed.

Two consequences. A code exchange with no preceding authorization request found
`client` undefined and failed at `client.id` with an unhandled TypeError and a
500, reachable unauthenticated. And the check that a code is redeemed by the
client it was issued to could be satisfied by any client beginning its own
authorization request first — a code issued to one client was redeemed by
another, returning an access token for the profile URL and scope it carried.

`consent.js` already signs `client_id` and `redirect_uri` into the code, and
nothing read them. Verify the code first, compare the request against those
claims, and reject a code missing either. PKCE keys off the challenge recorded
in the code, so `app.locals` is no longer read here at all.

`validateRedirect` is no longer called at redemption: the redirect was checked
against client metadata during the authorization request, leaving only the
match against the value the code was issued for.

Seven existing tests signed codes carrying neither claim — codes this server
cannot issue — and now sign what a real code carries. Two tests added, one per
failure.

Verified in the monorepo with this exact `lib/middleware/code.js` alongside the
beta.35 `grant_type` change: 70 tests, 70 passing. The fork's own integration
tests cannot run standalone (they need `@indiekit-test/*`), so that combined
run is the evidence.

Identical to the change proposed upstream in getindiekit/indiekit#893.

Release: 1.0.0-beta.36

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGHR7MuyvBaDbAFfAGUxeT
2026-08-20 15:40:02 +02:00
assets feat: initial commit - IndieAuth endpoint for Indiekit 2026-02-06 16:34:46 +01:00
lib fix: bind code exchange to the code's own claims 2026-08-20 15:40:02 +02:00
locales feat: initial commit - IndieAuth endpoint for Indiekit 2026-02-06 16:34:46 +01:00
test fix: bind code exchange to the code's own claims 2026-08-20 15:40:02 +02:00
views feat: initial commit - IndieAuth endpoint for Indiekit 2026-02-06 16:34:46 +01:00
.gitignore feat: initial commit - IndieAuth endpoint for Indiekit 2026-02-06 16:34:46 +01:00
CHANGELOG.md feat: initial commit - IndieAuth endpoint for Indiekit 2026-02-06 16:34:46 +01:00
CLAUDE.md docs: add fork notice to README, adopt version-in-package.json policy 2026-08-15 21:46:17 +02:00
index.js feat: initial commit - IndieAuth endpoint for Indiekit 2026-02-06 16:34:46 +01:00
package.json fix: bind code exchange to the code's own claims 2026-08-20 15:40:02 +02:00
README.md docs: add fork notice to README, adopt version-in-package.json policy 2026-08-15 21:46:17 +02:00

@rmdes/indiekit-endpoint-auth

IndieAuth authentication and authorization endpoint for Indiekit. Grants and verifies access tokens and authenticates users.

This is a fork of @indiekit/endpoint-auth with custom authentication fixes (see below).

Installation

npm install @rmdes/indiekit-endpoint-auth

Or via npm overrides (recommended for replacing the default package):

{
  "overrides": {
    "@indiekit/endpoint-auth": "npm:@rmdes/indiekit-endpoint-auth@^1.0.0-beta.31"
  }
}

Custom Fixes in This Fork

This fork includes the following improvements over the upstream package:

  1. Spec-Compliant redirect_uri Validation — Validates that redirect_uri has the same scheme, host, and port as client_id per IndieAuth specification (commit 3e69d16)
  2. Localhost Client Support — Handles localhost client IDs without attempting to fetch metadata (commit 134c820)
  3. Profile Scope Support — Adds support for IndieAuth profile scopes (commit 9d3351a)
  4. Security Middleware Fix — Prevents double next() calls in secret validation middleware (commit de7d8ca)

For full technical details, see CLAUDE.md in this repository.

Configuration

To customize the behavior of this plugin, add @rmdes/indiekit-endpoint-auth to your configuration:

import AuthorizationEndpoint from "@rmdes/indiekit-endpoint-auth";

export default {
  plugins: [
    new AuthorizationEndpoint({
      mountPath: "/auth", // Default: "/auth"
    }),
  ],
};

Environment Variables

Required:

  • SECRET - Strong random string used to sign and verify JWT tokens
  • PASSWORD_SECRET - Hashed and salted password for user authentication. Generate at /auth/new-password

Options

Option Type Default Description
mountPath string /auth Path to authorization endpoint. Must match your Indiekit instance URL path.

Endpoints

Authorization Flow

GET /auth — Start the authorization flow. Shows either documentation (if no params) or the consent form

GET /auth/consent — Display the authentication/authorization consent form

POST /auth/consent — Submit credentials and grant authorization. Returns authorization code

POST /auth/token — Exchange authorization code for access token

POST /auth/introspect — Verify and inspect an access token

Utility

GET /auth/new-password — Display password secret generator UI

POST /auth/new-password — Generate a new hashed PASSWORD_SECRET value

GET /.well-known/oauth-authorization-server — OAuth authorization server metadata

GET /.well-known/change-password — Redirect to password secret generator

How It Works

  1. Authorization Request — Client app redirects user to /auth?client_id=...&redirect_uri=...&state=...
  2. Consent — User enters their password to grant authorization
  3. Authorization Code — Server issues a one-time authorization code
  4. Token Exchange — Client exchanges code for long-lived access token
  5. Token Introspection — Any service can verify tokens by POST'ing to /auth/introspect

All tokens are JWTs signed with the SECRET environment variable.

Scopes

Supported Micropub scopes:

  • create — Create new posts
  • draft — Create draft posts
  • update — Update existing posts
  • delete — Delete posts
  • media — Upload media files

Supported Microsub scopes:

  • read — Read feeds
  • follow — Follow/subscribe to feeds
  • mute, block — Manage blocked feeds
  • channels — Create and manage feed channels

Unsupported scopes (shown as disabled in consent form):

  • email, profile — IndieAuth profile scopes

PKCE Support

If the client sends code_challenge and code_challenge_method, PKCE (Proof Key for Code Exchange) is required for token exchange. PKCE is optional but recommended for security, especially for mobile and single-page applications.

Client Information Discovery

The endpoint attempts to fetch client metadata in this order:

  1. JSON client metadata (preferred, per IndieAuth spec)
  2. h-app microformat (deprecated, backwards compatibility)
  3. Hostname fallback (from client_id URL)

License

MIT - Original work by Paul Robert Lloyd, custom fixes by Ricardo Mendes.