{"record":{"id":"96cd873d04a0e8e2","repo":"iflytek/astron-agent","slug":"malformed-bearer-credential","errorCode":null,"errorMessage":"malformed bearer credential","messagePattern":"malformed bearer credential","errorType":"exception","errorClass":"GatewayAuthException","httpStatus":null,"severity":"error","filePath":"console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/gateway/impl/GatewayAuthServiceImpl.java","lineNumber":29,"sourceCode":"\n    private static final String BEARER_PREFIX = \"Bearer \";\n\n    private final TenantGatewayAuthClient tenantClient;\n\n    public GatewayAuthServiceImpl(TenantGatewayAuthClient tenantClient) {\n        this.tenantClient = tenantClient;\n    }\n\n    @Override\n    public String authenticateWorkflow(String authorizationHeader) {\n        if (!StringUtils.hasText(authorizationHeader) || !authorizationHeader.startsWith(BEARER_PREFIX)) {\n            throw new GatewayAuthException(\"missing bearer credential\");\n        }\n\n        String credential = authorizationHeader.substring(BEARER_PREFIX.length()).trim();\n        String[] parts = credential.split(\":\", -1);\n        if (parts.length != 2 || !StringUtils.hasText(parts[0]) || !StringUtils.hasText(parts[1])) {\n            throw new GatewayAuthException(\"malformed bearer credential\");\n        }\n\n        return tenantClient.verify(parts[0], parts[1])\n                .filter(StringUtils::hasText)\n                .orElseThrow(() -> new GatewayAuthException(\"invalid app credential\"));\n    }\n}\n","sourceCodeStart":11,"sourceCodeEnd":37,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/gateway/impl/GatewayAuthServiceImpl.java#L11-L37","documentation":"After stripping the Bearer prefix, authenticateWorkflow expects the credential to be exactly two non-empty segments joined by ':' (appKey:appSecret). Any credential that splits into more or fewer parts, or has an empty segment, throws GatewayAuthException(\"malformed bearer credential\").","triggerScenarios":"Sending 'Authorization: Bearer onlyKey' (no colon), 'Bearer a:b:c' (extra colon), 'Bearer :secret' or 'Bearer key:' (empty segment), or a token containing whitespace/encoded characters that break the split.\",\"commonSituations","commonSituations":"Developers pasting a raw appKey without the secret; URL-encoding the colon (%3A); putting the whole JSON credential object into the header; config templates with placeholder colons left unresolved.","solutions":["Send the credential as exactly 'Bearer <appKey>:<appSecret>' with one colon and both parts non-empty.","Do not URL-encode the colon inside the Bearer token.","Confirm the credential was not truncated or wrapped (quotes/newlines) by the client config."],"exampleFix":"// before\nAuthorization: Bearer myAppKey\n// after\nAuthorization: Bearer myAppKey:myAppSecret","handlingStrategy":"validation","validationCode":"const cred = authHeader.slice('Bearer '.length); if (!/^[^:]+:[^:]+$/.test(cred)) { throw new Error('credential must be appKey:appSecret'); }","typeGuard":"function isWellFormedCredential(h) { const parts = (h || '').replace(/^Bearer\\s+/, '').split(':'); return parts.length === 2 && parts[0] && parts[1]; }","tryCatchPattern":null,"preventionTips":["Store the full appKey:appSecret credential as a single config value.","Do not URL-encode the colon inside the Bearer token.","Validate credential format at client startup."],"tags":["auth","http-header","format"],"backgroundTag":"invalid-argument-format","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}