Skip to content

[Feature] Service Tokens for the API #881

@chrismaddalena

Description

@chrismaddalena

Feature Description

We want to implement scoped API tokens so users are not limited to using their personal JWTs when those permissions are not required.

Are you intending to implement this feature?

Yes.

Current Behavior

API tokens are JWTs that represent their users and carry their users' permissions. There is no way to limit the scope of permissions for different jobs.

Desired Behavior

To begin, we offer the option to generate "service tokens" that have specific purposes and follow this criteria:

  1. Use opaque tokens instead of JWTs (easier to copy/paste and use)
  2. Identify the tokens with a prefix—e.g., gwst_
  3. Scoped to a specific purpose—e.g., activity logging, read-access

We expand this feature to add more options and, eventually, the option to create tokens with granular permission sets.

Use Case

A service token for mythic_sync that has read access to a specific Oplog and read/write access to that Oplog's entries. This is a much better scenario than using a user's JWT, particularly in cases where the logging utility is in a shared environment. Unless someone is working alone, this is often unavoidable because the entire team will have root access to these systems.

The above use case is the primary objective of the MVP.

Another common use case is granting access to an LLM. For most use cases, the LLM only needs read-access, and may only need read-access to a specific project. That is sufficient for an LLM that may be looking at Ghostwriter for analytics or report writing without exposing potentially dangerous write permissions.

Implementation Suggestions

Add a new non-human auth path alongside existing user JWT/API tokens:

  • ServicePrincipal
    • A non-human actor record
    • Created automatically when a user creates a new service token
    • Tracks name, service_type, created_by, and active status
  • ServiceToken
    • Opaque credential in the form gwst_<prefix>_<secret>
    • Stores hashed secret, expiry, revocation state, last-used timestamp, creator, and owning ServicePrincipal
  • ServiceTokenPermission
    • Generic permission rows attached to the token
    • MVP uses these to represent one scoped Oplog permission set

Hasura integration:

  • GraphqlAuthenticationWebhook recognizes service tokens
  • For valid service tokens it returns:
    • X-Hasura-Role=service
    • X-Hasura-Service-Principal-Id=<id>
    • X-Hasura-Allowed-Oplog-Id=<oplog_id>
    • X-Hasura-Principal-Type=service
    • X-Hasura-User-Name=<service principal name>
  • It does not return X-Hasura-User-Id for service tokens
  • Service-token auth is based only on token scope, never on the permissions of the real user who created it

Add a service role to Hasura for permission checks. We can also add a X-Hasura-Allowed-Project-Ids header for enabling project access for an LLM token. With Hasura's _in operator, we can check a list of project IDs to enable access to multiple projects.

User flow:

  1. Visit the user profile as you would to create an existing token
  2. Click Create for a new service token section
  3. Choose to create a new Service Principal or reuse an existing one
  4. Provide a name and select options

This flow enables a user to seamlessly create a new Service Principal or reuse an existing one to organize their tokens. For example:

  • Service Principal: Mythic Sync
    • Service Token: ACME Q2 Penetration Test
    • Service Token: SpecterOps Q2 Red Team
  • Service Principal: LLM
    • Service Token: AWS Bedrock
    • Service Token: Ghostwriter MCP

Additional Information

Some of the described implementation is somewhat overkill for the MVP. The intent is to create a foundation we can use to build out this feature depending on future demand.

Metadata

Metadata

Labels

Type

No type
No fields configured for issues without a type.

Projects

Status

In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions