Skip to content

Flutter SDK emits no PKCE code_verifier, so no published backend client can exchange its authorization code #1

Description

@skhawcx

Summary

hawcx_flutter_sdk emits an authorization code that no published Hawcx backend client can exchange. Flutter customers currently have no supported way to complete backend verification.

Every published Hawcx backend client requires a PKCE code_verifier alongside the authorization code. The Flutter SDK never produces one.

Evidence

The Flutter SDK emits no verifier. In the published hawcx_flutter_sdk 1.0.5 archive from pub.dev, lib/ contains zero references to codeVerifier or code_verifier. AuthorizationCodePayload (lib/src/models/events.dart:185) carries code and expiresIn only.

Every backend client requires one.

Client Call Behaviour without a verifier
@hawcx/oauth-client 5.2.0 exchangeCode(code, codeVerifier) throws TokenExchangeError: codeVerifier is required
@hawcx/oauth-client 5.2.0, legacy mode new HawcxOAuth({ configId, baseUrl }) then exchangeCode same guard, same throw
Java new TokenRequest(configId, authCode, codeVerifier) no verifier-less constructor exists

From published @hawcx/oauth-client@5.2.0, dist/oauth.js:

async exchangeCode(code, codeVerifier, redirectUri, expectedNonce) {
    if (!code)
        throw new errors_1.TokenExchangeError('code is required');
    if (!codeVerifier)
        throw new errors_1.TokenExchangeError('codeVerifier is required');
    const body = new URLSearchParams();
    body.append('grant_type', 'authorization_code');
    body.append('code', code);
    body.append('code_verifier', codeVerifier);

The guard is unconditional. Legacy mode relaxes iss and aud verification but not this.

How this surfaced

The Flutter docs page carried a Node/Express backend snippet importing exchangeCodeForTokenAndClaims, OAuthExchangeError and JWTVerificationError from @hawcx/oauth-client. None of the three has ever existed in that package. Tracked as B7 on hawcx/sdk_docs#81.

The obvious fix was to swap them for the real symbols (HawcxOAuth, TokenExchangeError, TokenVerificationError). That fix does not work: the corrected snippet needs a codeVerifier the Flutter SDK does not emit, so it would throw on the first call. The fabricated symbols were hiding a real product gap.

React Native contrast

React Native has the same legacy defect but a way out. @hawcx/react-native-sdk types the legacy AuthorizationCodePayload as { code, expiresIn } and references codeVerifier only in its V6 files (src/v6Types.ts, src/v6Normalization.ts, ios/HawcxV6BridgeSupport.swift, android/.../v6/HawcxV6Bridge.kt). The V6 flow generates PKCE natively and returns codeVerifier in the completed payload, so a V6 React Native app can exchange normally.

Flutter has no V6 equivalent, in the SDK or in the docs.

Impact

Any Flutter customer following the documented flow reaches step 6, sending the code to their backend, and cannot proceed. There is no workaround at the SDK level.

Suggested resolution

Either surface a PKCE codeVerifier on the Flutter authorization-code payload the way the React Native V6 bridge does, or ship a Flutter V6 flow. Whichever lands, the docs page needs a matching update.

Docs status

The unimplementable snippet has been removed from both mobile pages rather than left to mislead. The Flutter page now states the constraint and points at support; the React Native page points at the V6 flow. Branch docs/fix-b7-mobile-backend on hawcx/sdk_docs, not yet pushed.

The contract-check CI harness on sdk_docs catches this class automatically: it verifies every symbol the docs import against the published package entry point.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions