This note captures the current findings around using the Forgejo or Codeberg fj CLI context for API automation, creating managed repo-user tokens, and inviting users who do not yet exist on the instance.
The work should be treated as deferred implementation research until Dataverket has a local or development Forgejo instance for safe iteration.
Problem
Dataverket wants a convenient operator workflow for the following tasks:
- reuse an existing
fjlogin context instead of inventing a separate login flow - manage per-repo or per-team service users
- create multiple API tokens per managed user, with different access rights
- store the resulting secrets in the existing SOPS-backed
infralayout - support both Codeberg and self-hosted Forgejo where possible
The main question is whether an API helper can safely reuse fj context for all of this, or whether some parts of the workflow are intentionally blocked by Forgejo.
Verified Findings
fj context reuse is useful, but only for part of the workflow
Forgejo supports OAuth2 authorization code flow with PKCE for public clients. This is sufficient for a CLI to represent the current user for normal API operations and host or account discovery.
However, Forgejo does not currently implement OAuth2 scopes. OAuth2 tokens therefore act with broad authority on behalf of the user and are not a safe substitute for scoped personal access tokens.
This means a future helper can likely reuse fj context for:
- selecting the current host and authenticated account
- normal API-backed operations such as listing repos, users, and memberships
- bootstrapping operator-side context for later automation steps
It should not assume that reused OAuth2 state is enough to mint scoped PATs.
PAT creation is intentionally constrained in Forgejo
The Forgejo API includes a PAT creation handler in:
external/forgejo/routers/api/v1/user/app.go
Specifically, CreateAccessToken exists and creates an access token for the selected user context.
But the corresponding route wiring in:
external/forgejo/routers/api/v1/api.go
shows that the endpoint is guarded by both:
reqBasicOrRevProxyAuth()reqSelfOrAdmin()
This is the key constraint.
For Dataverket, it means a helper cannot rely on a normal token-authenticated API session to create PATs on Codeberg. The server-side route deliberately requires stronger authentication semantics than ordinary token-based API access.
This aligns with Forgejo’s security posture: PAT minting is not treated as just another token-authenticated operation.
Existing-user membership is API-friendly
Forgejo does expose team membership management for existing accounts through the public API. The relevant code is in:
external/forgejo/routers/api/v1/org/team.go
The AddTeamMember path accepts a team ID and an existing username. This is a good fit for later automation when the target user account already exists.
This part of the eventual workflow can likely be implemented cleanly through an API helper that reuses the operator’s existing fj context.
Inviting non-existing users by email is web-only today
The relevant behavior lives in the web layer, not the public API.
In:
external/forgejo/routers/web/org/teams.go
the team add flow checks whether the submitted identifier resolves to a user. If not, and mail is enabled and the input validates as an email address, Forgejo creates a team invite instead.
The invite model is stored in:
external/forgejo/models/organization/team_invite.go
This confirms that email-based invites for non-existing users exist, but only through the web handler path.
The public API path in:
external/forgejo/routers/api/v1/org/team.go
only supports adding an existing user by username. It does not expose a corresponding email invite endpoint.
For Dataverket, this means a future helper cannot implement non-existing-user invites through the public API alone. If this workflow is required, it will need a browser-assisted fallback or an upstream Forgejo change.
Official Documentation Checked
The following official documentation supports the code-level findings:
- Forgejo OAuth2 provider user guide:
https://forgejo.org/docs/latest/user/oauth2-provider/ - Forgejo OAuth2 provider admin guide:
https://forgejo.org/docs/latest/admin/advanced/oauth2-provider/ - Codeberg access token guide:
https://docs.codeberg.org/advanced/access-token/
Relevant points from those docs:
- Forgejo supports OAuth2 authorization code flow and PKCE.
- Forgejo ships pre-registered OAuth2 applications for common Git credential helpers.
- Forgejo documents that OAuth2 scopes are not yet implemented.
- Codeberg documents PAT creation primarily as a manual web workflow under user settings.
What This Means For Dataverket
Supported direction later
A future helper can probably reuse fj context for:
- host and account discovery
- operator-side API access using the current authenticated identity
- reconciling repo or team membership for users that already exist
- generating plans for which tokens, repos, and secret files should exist
Not supported today
A future helper should not assume it can:
- mint PATs on Codeberg purely from reused OAuth2 login state
- invite non-existing users by email via the public Forgejo API
Plausible fallback direction later
The most realistic fallback path is a browser-assisted workflow for the parts Forgejo exposes only in the web UI:
- PAT creation on Codeberg and possibly self-hosted Forgejo
- email invite flow for non-existing users
This should be treated as controlled automation, not hidden headless behavior. Manual login or MFA pauses are likely to remain part of the flow.
Likely Integration Direction
If Dataverket implements this later, the most natural CLI integration point is dv forgejo.
Reasons:
- the root CLI already uses a registry-based command model in
bootstrap/cmd/dv/main.go - sibling repos already provide
dvsubcommands that are linked into the root binary - the CLI naming ADR in
bootstrap/docs/decisions/002-cli-naming-and-structure.mdplaces shared operator tooling under thedvfamily
This note is not an ADR and does not commit Dataverket to a final command schema. It only records the current best implementation direction.
Secret Storage Direction
Any later token automation should reuse the existing SOPS pattern in:
infra/.sops.yamlinfra/env/codeberg/config.yamlinfra/env/kode/config.yaml
Managed repo-user PATs should be stored separately from the current Forgejo provider token files used by infrastructure automation.
That separation matters because the provider token is an operator or automation credential for managing Forgejo itself, while the managed-user PATs are workload or repo-scoped credentials with their own rotation and review lifecycle.
Local Development Prerequisite
Implementation should wait until Dataverket has a local or development Forgejo instance with:
- test users
- test teams or repos
- reproducible authentication setup
- optional mail behavior if invite flows are to be exercised
Without that environment, the work would be too dependent on production Codeberg behavior and too awkward to validate safely.
Proposed Next Steps Once Local Forgejo Exists
Start with small slices in this order:
- add an adapter that reads
fjcontext for host and current account selection - define a declarative managed-user and token inventory for Dataverket
- implement API-backed reconciliation for existing-user memberships
- write resulting secrets into the existing SOPS layout under
infra - add browser-assisted fallback flows for PAT creation and email invites where the API does not support them
Scope Boundary
This document records verified research and an implementation direction.
It does not define:
- a final user-facing CLI interface
- a committed secret schema
- production-ready automation behavior
- any guarantee that
fjexposes a stable public context format suitable for direct reuse
Those details should be settled only after a local Forgejo instance exists and the flows can be exercised end to end.