Add license checksum claim to the Orbit JWT
What does this MR do and why?
Orbit (orbit-server) needs to check GitLab credits quota with CustomersDot on self-managed and Dedicated. It can't hold the CustomersDot admin token there because it runs on customer infrastructure.
CustomersDot already authenticates self-managed instances by license checksum (X-License-Token), as Rails does for Duo quota checks. So Rails now puts License.current.checksum in the Orbit JWT, only on the self-managed realm (this includes Dedicated) with an online cloud license; CustomersDot rejects other license types. Only the checksum is sent, never the license. Orbit ignores unknown claims, so this is safe before the Orbit side ships.
What changes:
Analytics::KnowledgeGraph::JwtAuthadds alicense_checksumclaim (the 64-char SHA256 fromLicense#checksum).- Added only when
CloudConnector.gitlab_realmisself-managed(includes Dedicated) andLicense.current.online_cloud_license?. Omitted on GitLab.com, and for offline cloud, legacy, or missing licenses. - Expired licenses are not filtered here; CustomersDot owns grace-period handling.
- No feature flag: Orbit ignores unknown claims, quota checks stay off by default on self-managed Orbit, and CustomersDot has its own kill switches.
- Both ways Rails sends the JWT to Orbit (direct gRPC, and streaming through Workhorse) build it in
JwtAuth.build_payload, so this one change covers both.
Security notes
Low risk; AppSec review requested.
- The checksum can't be used to recover the license and can't reach seat links or Cloud Connector token minting at CustomersDot; those need the raw license key.
- A leaked checksum lets someone read quota verdicts and trial info for that customer's own subscription. The instance admin already has more than that.
- The JWT is only sent over TLS or to private/loopback addresses (existing guard in
GrpcClientandEE::Gitlab::Workhorse). It is signed, not encrypted, so TLS is recommended for the Rails to Orbit endpoint. - Nothing logs the token or payload.
- The same value is already sent to version.gitlab.com in Service Ping as
license_sha256. - Orbit-side handling (redaction, marking the header sensitive, the new quota auth mode) is in a separate knowledge-graph MR.
References
- Related to https://gitlab.com/gitlab-org/gitlab/-/work_items/630306
- Earlier Rails-side quota gate draft: !257039 (closed)
- Cloud Connector token work for Orbit billing: https://gitlab.com/gitlab-org/orbit/knowledge-graph/-/work_items/1229
Screenshots or screen recordings
Not applicable, backend-only change with no UI.
How to set up and validate locally
-
Activate an online cloud license on a self-managed GDK (not GitLab.com mode).
-
In the Rails console:
user = User.first ctx = Analytics::KnowledgeGraph::RequestContext.new(source_type: Analytics::KnowledgeGraph::SourceType::REST) token = Analytics::KnowledgeGraph::JwtAuth.generate_token(user: user, request_context: ctx) payload = JWT.decode(token, Analytics::KnowledgeGraph::JwtAuth.secret, true, { algorithm: 'HS256' }).first payload['license_checksum'] == License.current.checksum # => true payload['realm'] # => "self-managed" -
With an offline or legacy license, or in GitLab.com mode,
payload.key?('license_checksum')returnsfalse. -
Specs:
bin/rspec ee/spec/lib/analytics/knowledge_graph/jwt_auth_spec.rb
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.