{"record":{"id":"dd27bb214af62798","repo":"lcobucci/jwt","slug":"builder-withclaim-is-meant-to-be-used-for-non-registered","errorCode":null,"errorMessage":"Builder#withClaim() is meant to be used for non-registered claims, check the documentation on how to set claim \"%s\"","messagePattern":"Builder#withClaim\\(\\) is meant to be used for non-registered claims, check the documentation on how to set claim \"(.+?)\"","errorType":"exception","errorClass":"Lcobucci\\JWT\\Token\\RegisteredClaimGiven","httpStatus":null,"severity":"error","filePath":"src/Token/Builder.php","lineNumber":95,"sourceCode":"    }\n\n    public function withHeader(string $name, mixed $value): BuilderInterface\n    {\n        $headers        = $this->headers;\n        $headers[$name] = $value;\n\n        return new self(\n            $this->encoder,\n            $this->claimFormatter,\n            $headers,\n            $this->claims,\n        );\n    }\n\n    public function withClaim(string $name, mixed $value): BuilderInterface\n    {\n        if (in_array($name, RegisteredClaims::ALL, true)) {\n            throw RegisteredClaimGiven::forClaim($name);\n        }\n\n        return $this->newWithClaim($name, $value);\n    }\n\n    /** @param non-empty-string $name */\n    private function newWithClaim(string $name, mixed $value): BuilderInterface\n    {\n        $claims        = $this->claims;\n        $claims[$name] = $value;\n\n        return new self(\n            $this->encoder,\n            $this->claimFormatter,\n            $this->headers,\n            $claims,\n        );\n    }","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/lcobucci/jwt/blob/375813049c24c7111bda8b6884c57b071ceb2fe7/src/Token/Builder.php#L77-L113","documentation":"Builder::withClaim() is reserved for private (non-registered) claims. If the claim name is one of the IANA-registered JWT claims (iss, sub, aud, exp, nbf, iat, jti, etc.), the builder refuses and throws RegisteredClaimGiven::forClaim(), because registered claims need typed values and dedicated methods.","triggerScenarios":"Calling $builder->withClaim('iss', ...), withClaim('exp', ...), withClaim('aud', ...) or any other name present in lcobucci\\jwt\\signing or Token\\RegisteredClaims::ALL.","commonSituations":"Copy-pasted code building tokens that sets standard claims generically; migration from another JWT library where all claims were set through one method; setting 'exp' or 'iat' as raw ints instead of using the typed API (which handles DateTimeImmutable conversion).","solutions":["Use the dedicated builder methods: issuedBy(), relatedTo(), permittedFor(), identifiedBy(), canOnlyBeUsedAfter(), expiresAt(), issuedAt()","For time claims pass DateTimeImmutable objects to expiresAt()/issuedAt()/canOnlyBeUsedAfter() rather than raw values via withClaim","Keep withClaim() only for custom/private claim names not in RegisteredClaims::ALL"],"exampleFix":"// before\n$builder->withClaim('iss', 'https://my.issuer')->withClaim('exp', time() + 3600);\n// after\n$builder->issuedBy('https://my.issuer')\n        ->issuedAt(new DateTimeImmutable())\n        ->expiresAt(new DateTimeImmutable('+1 hour'));","handlingStrategy":"validation","validationCode":"if (in_array($name, Lcobucci\\JWT\\Token\\RegisteredClaims::ALL, true)) { useDedicatedBuilderMethod($name); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Learn the dedicated builder methods for registered claims (issuedBy, expiresAt, etc.)","Restrict withClaim usage to custom names via code review or a thin wrapper API","When migrating libraries, map every old generic set() call to the typed API"],"tags":["jwt","builder","claims","php"],"backgroundTag":"invalid-argument-value","analyzedSha":"375813049c24c7111bda8b6884c57b071ceb2fe7","analyzedAt":"2026-09-14T11:12:28.004Z","contentChangedAt":"2026-09-14T11:12:28.004Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}