floci-io/floci · error · VtlErrorSignal

Unauthorized

Unauthorized

Error message

Not Authorized

What it means

Implements $util.unauthorized(): the VTL equivalent of rejecting a request for missing/failed authorization. The resolver aborts with message 'Not Authorized' and errorType 'Unauthorized', mirroring AppSync's behavior when authorization checks in a mapping template fail.

Source

Thrown at src/main/java/io/github/hectorvent/floci/services/appsync/graphql/util/AppSyncUtil.java:248

    }

    public void appendError(String message, String errorType, Object data, Object errorInfo) {
        appendErrorInternal(message, errorType, data, errorInfo);
    }

    private void appendErrorInternal(String message, String errorType, Object data, Object errorInfo) {
        if (errorList != null) {
            Map<String, Object> error = new LinkedHashMap<>();
            error.put("message", message);
            error.put("type", errorType);
            if (data != null) error.put("data", data);
            if (errorInfo != null) error.put("errorInfo", errorInfo);
            errorList.add(error);
        }
    }

    public void unauthorized() {
        throw new VtlErrorSignal("Not Authorized", "Unauthorized", null, null);
    }

    public void validate(boolean condition, String message) {
        validate(condition, message, "CustomTemplateException");
    }

    public void validate(boolean condition, String message, String errorType) {
        validate(condition, message, errorType, null);
    }

    public void validate(boolean condition, String message, String errorType, Object data) {
        if (!condition) {
            throw new VtlErrorSignal(message, errorType, data, null);
        }
    }
}

View on GitHub (pinned to 62ff490619)

Solutions

  1. Send the correct authorization for the API's auth mode: signed requests (SigV4 for IAM), Authorization header (Cognito JWT), or x-api-key header.
  2. Verify the identity claim the template checks actually exists, e.g. decode the JWT and inspect $ctx.identity.claims.
  3. Relax or fix the template guard if it rejects legitimate users (wrong group name, null-check inverted).
  4. In the emulator, ensure the AppSync API's default authentication mode matches what the client uses.

Example fix

## before
#if(!$ctx.identity.claims.get("cognito:groups").contains("admins"))
  $util.unauthorized()
#end

## after
#set($groups = $util.defaultIfNull($ctx.identity.claims.get("cognito:groups"), []))
#if(!$groups.contains("admins"))
  $util.unauthorized()
#end
Defensive patterns

Strategy: validation

Validate before calling

// Client: prove credentials are present before the GraphQL call
if (authMode == IAM && signingCredentials == null) throw new IllegalStateException("IAM credentials required");
if (authMode == API_KEY && apiKey == null) throw new IllegalStateException("API key required");
if (authMode == USER_POOLS && jwt == null) throw new IllegalStateException("Cognito token required");

Try / catch

if (response.hasErrors() && response.getErrors().stream()
        .anyMatch(er -> "Unauthorized".equals(er.getErrorType()) || "Not Authorized".equals(er.getMessage()))) {
    throw new UnauthorizedException("refresh credentials and retry");
}

Prevention

When it happens

Trigger: A request/response mapping template calls $util.unauthorized() — e.g. #if($ctx.identity == null) or a group-membership check like #if(!$ctx.identity.claims.get("cognito:groups").contains("admins")) — and the guard trips. Common in field-level authorization on top of API-level auth.

Common situations: Cognito/API-key authorizers where the test client sends no or wrong credentials; AppSync API configured with IAM auth but the request signed with a different mechanism; role/group claim names that don't match what the template checks after migrating identity providers.

Related errors


AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14). Data as JSON: /api/errors/dc7b398fe4eb3a71. Report an issue: GitHub.