gitroomhq/postiz-app · error · HttpException

Only the S256 code_challenge_method is supported

Error message

Only the S256 code_challenge_method is supported

What it means

Thrown when the authorization request includes a code_challenge with a code_challenge_method other than S256. This server deliberately supports only the S256 (SHA-256 hashed) PKCE method; the plaintext 'plain' method is rejected because it offers weaker protection.

Source

Thrown at libraries/nestjs-libraries/src/database/prisma/oauth/oauth.service.ts:210

    // Dynamically registered clients must use their registered redirect_uris
    // and PKCE; statically registered apps keep the existing lenient flow
    if (app.dynamic) {
      const registered: string[] = JSON.parse(app.redirectUris || '[]');
      if (!options?.redirectUri || !registered.includes(options.redirectUri)) {
        throw new HttpException('Invalid redirect_uri', HttpStatus.BAD_REQUEST);
      }
      if (app.tokenEndpointAuthMethod === 'none' && !options?.codeChallenge) {
        throw new HttpException(
          'code_challenge is required for this client',
          HttpStatus.BAD_REQUEST
        );
      }
      if (
        options?.codeChallenge &&
        options?.codeChallengeMethod &&
        options.codeChallengeMethod !== 'S256'
      ) {
        throw new HttpException(
          'Only the S256 code_challenge_method is supported',
          HttpStatus.BAD_REQUEST
        );
      }
    }

    return app;
  }

  async createAuthorizationCode(
    oauthAppId: string,
    userId: string,
    organizationId: string,
    pkce?: {
      codeChallenge?: string;
      codeChallengeMethod?: string;
      redirectUri?: string;
    }

View on GitHub (pinned to 0f1647f749)

Solutions

  1. Generate the challenge as base64url(sha256(verifier)) and send code_challenge_method=S256
  2. Upgrade/replace the client library that defaults to 'plain'
  3. Ensure the page runs in a secure context (https or localhost) so crypto.subtle is available for S256

Example fix

// before
const challenge = base64url(verifier); // plain
// after
const challenge = base64url(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier)));
Defensive patterns

Strategy: validation

Validate before calling

if (codeChallenge && codeChallengeMethod !== 'S256') {
  throw new Error('Only S256 PKCE is supported by this server');
}

Type guard

const isS256 = (m?: string): boolean => !m || m === 'S256';

Try / catch

try { await authorize(req); } catch (e) { if (/S256/.test(e.message)) { codeChallengeMethod = 'S256'; return authorize(req); } throw e; }

Prevention

When it happens

Trigger: Sending code_challenge_method=plain (or any value other than S256) alongside a code_challenge on a dynamic client's authorization request.

Common situations: Hand-rolled PKCE that defaults to plain; older client libraries defaulting to plain; environment/browser lacking crypto.subtle so code falls back to plain challenge.

Related errors


AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27). Data as JSON: /api/errors/4d7b44f54dc071ec. Report an issue: GitHub.