Documentation
¶
Overview ¶
Package auth — audit_middleware.go
Chi middleware that watches mutating routes and records a row in audit_log when the response is a 2xx. Wraps the response writer to capture the final status code and reads the *model.User from the request context (so it must be installed AFTER auth.Middleware).
Package auth defines the AuthDriver interface, registry, and middleware.
Drivers live under auth/drivers/ and self-register via init() blocks. The middleware reads request headers/cookies, attempts each enabled driver in turn, and stores the resulting *model.User on the request context for downstream handlers.
Index ¶
- Constants
- Variables
- func AIAdminAction(method, path, id, name string) (string, string, string)
- func APITokenMiddleware(store db.Store) func(http.Handler) http.Handler
- func ActionForPath(method, p, id, name string) (string, string, string)
- func AddAuditDetail(ctx context.Context, key string, v interface{})
- func AllowVerb(w http.ResponseWriter, r *http.Request, verb string) bool
- func AnnotateToken(store db.Store) func(http.Handler) http.Handler
- func AnnotateUser() func(http.Handler) http.Handler
- func AuditMiddleware(store db.Store) func(http.Handler) http.Handler
- func CallerMayAdminister(ctx context.Context) bool
- func CfgBool(cfg map[string]any, key string) bool
- func CfgString(cfg map[string]any, key string) string
- func LoginAllowed(ctx context.Context, store db.Store, multiTenant bool, u *model.User) bool
- func LoginHostFrom(ctx context.Context) string
- func Middleware(required bool) func(http.Handler) http.Handler
- func MiddlewareWithToken(store db.Store, required bool) func(http.Handler) http.Handler
- func Names() []string
- func NetReason(err error) string
- func ProbeOKAll(checks []ProbeCheck) bool
- func ProvisionUser(ctx context.Context, store ProvisionStore, h TenantHoming, ...) (*model.User, error)
- func RefuseVerb(w http.ResponseWriter, verb string)
- func Register(name string, f Factory)
- func RequireAdmin(next http.Handler) http.Handler
- func RequireAdminToken(next http.Handler) http.Handler
- func RequireScope(scope string) func(http.Handler) http.Handler
- func RequireVerb(verb string) func(http.Handler) http.Handler
- func ScopeForUser(ctx context.Context, store db.Store, u *model.User) *tenant.Scope
- func SetAuditTarget(ctx context.Context, id, name string)
- func SetEnabled(drivers []Driver)
- func SetPermissionStore(store db.Store)
- func TenantResolver(store db.Store, multiTenant bool) func(http.Handler) http.Handler
- func TokenAllows(ctx context.Context, verb string) bool
- func TokenFrom(ctx context.Context) *model.APIToken
- func TokenIsConfined(tok *model.APIToken) bool
- func TokenMayAdminister(tok *model.APIToken) bool
- func TokenMayBeUsed(ctx context.Context, store db.Store, u *model.User, tok *model.APIToken) bool
- func TokenPermission(tok *model.APIToken) perm.Perm
- func TokenUserFrom(ctx context.Context) string
- func TwoFactorPending(ctx context.Context, store db.Store, u *model.User) bool
- func TwoFactorPendingAllowed(path string) bool
- func UserFrom(ctx context.Context) *model.User
- func WithLoginHost(ctx context.Context, host string) context.Context
- func WithRequestLoginHost(ctx context.Context, r *http.Request) context.Context
- func WithToken(ctx context.Context, t *model.APIToken) context.Context
- func WithTokenUser(ctx context.Context, username string) context.Context
- func WithUser(ctx context.Context, u *model.User) context.Context
- type AuditDetail
- type Capabilities
- type Driver
- type Factory
- type LoginChain
- type LoginDriver
- type OIDCDriver
- type OIDCLogoutDriver
- type ProbeCheck
- type Prober
- type ProvisionStore
- type TenantHoming
- type TokenAuthenticator
Constants ¶
const ( // ProbeOK: this step was checked and holds. ProbeOK = "ok" // ProbeFail: this step was checked and does not hold. ProbeFail = "fail" // ProbeUnchecked: this step cannot be checked without a person signing // in (an OIDC redirect address, a public client). Said, never assumed. ProbeUnchecked = "unchecked" )
Probe statuses.
const ( VerbRead = "read" VerbWrite = "write" VerbDelete = "delete" )
The file verbs an API token can carry. They mirror drivers/apitoken's ScopeRead / ScopeWrite / ScopeDelete, declared here too because the driver imports this package and not the reverse.
Variables ¶
var ErrNoTenantForLogin = errors.New("auth: cannot determine which tenant this login belongs to")
ErrNoTenantForLogin is returned when a multi-tenant install cannot tell which tenant a just-in-time account belongs to.
⚠ It is deliberately a REFUSAL and not a fallback. The only fallback available is `default`, and homing a directory user there is the bug: it hands a confine-exempt, every-storage account to whoever the directory says exists. Refusing costs an operator one config line (`provider:`) or one DNS host; the fallback costs them the tenant boundary.
ErrUnauthorized is returned when no driver could authenticate a request.
Functions ¶
func AIAdminAction ¶
AIAdminAction derives the audit (action, targetType, targetID) for a request on the AI admin surface (/api/ai/admin/*). It normalizes the path down to the native /api/admin/* form, reuses ActionForPath's mapping, and prefixes the resulting action with "ai." so AI-token-driven admin writes are clearly distinguishable from native-panel ones in the Audit page. id/name are the corresponding chi URL params ("" when absent). Returns an empty action when the call isn't an auditable mutating admin op.
Used both by the HTTP AuditMiddleware (for /api/ai/admin REST calls) and by the MCP admin tools (which bypass HTTP middleware and audit in-process).
func APITokenMiddleware ¶
APITokenMiddleware authenticates a request strictly via an API token (X-Filex-Token or Authorization: Bearer), attaches both the bound user and the matched token to the context, and rejects anything else with 401.
Unlike the generic Middleware chain it does NOT accept cookie sessions — the AI/MCP namespace is token-only by design. Use RequireScope after it to gate individual verbs.
func ActionForPath ¶
ActionForPath maps a (method, path) pair to (action, target_type, target_id).
The path matching uses strings.HasPrefix on /api/admin/storages/ etc. so trailing slashes / IDs are handled uniformly. We intentionally don't try to read JSON bodies — only URL-derivable identifiers. id/name are the already-resolved chi URL params (passed in so this function is reusable outside an *http.Request context, e.g. from the in-process MCP invoker).
func AddAuditDetail ¶
AddAuditDetail records one fact for the request's audit row; a no-op when the request is not being audited.
func AllowVerb ¶ added in v0.49.0
AllowVerb is the in-handler form, for a route whose verb depends on the request (POST /api/files/manager?action=…, POST /api/files/ops {kind}). It answers the refusal itself and reports whether the handler may go on.
func AnnotateToken ¶
AnnotateToken attaches a valid API token to the context and NOTHING else. It never authenticates a user, never consults the session drivers, and — the whole point — never rejects: an unknown, revoked, expired or malformed token, a disabled owner, a bogus X-Filex-Token-User all simply leave the context untouched and the request proceeds as anonymous.
It exists for PUBLIC routes that must merely describe the caller — /api/files/capabilities reports `caller_kind` so the explorer knows whether to draw a person's surfaces. Reaching for MiddlewareWithToken there was wrong in a way that only shows up later: that chain answers 403 to a disabled account, so a disabled user's browser (which still holds a cookie) would have had the LOGIN page's capabilities probe fail closed. A public probe that can fail is a worse trade than a capability field.
⚠ Do not add a rejection path here. If a route needs one it needs a different middleware; this one's contract is that a public page can always get an answer.
func AnnotateUser ¶
AnnotateUser attaches the caller's user to the context when a credential resolves to one, and NOTHING else. It never rejects.
Middleware(false) is nearly this, but it still answers 403 for a disabled account — which is why /api/capabilities cannot use it: that route is fetched by the login screen and the public share pages, and a disabled user's browser still holds a cookie. Here a credential that does not work is simply an anonymous caller.
The one thing the annotation buys is the ability to answer a PUBLIC endpoint differently for a stranger: /api/capabilities publishes the operator's external service hosts, and a caller with no credential has no business learning them (see handlers.Capabilities).
⚠ Cheap on the anonymous path: every driver returns ErrUnauthorized immediately when the request carries no credential of its kind — no database round trip, no LDAP bind.
func AuditMiddleware ¶
AuditMiddleware returns a chi middleware that records audit_log entries for successful (2xx) mutating requests on a curated set of paths.
func CallerMayAdminister ¶
CallerMayAdminister reports whether the request's caller may use an account-wide operator power: the account is an administrator AND, when the request was authenticated by a token, that token may administer.
A session (no token on the context) is judged by the account alone, exactly as before.
func CfgBool ¶
CfgBool reads a configuration value as a bool. The settings table stores every value as a string, so "true"/"1"/"yes"/"on" count as well as a JSON true.
func LoginAllowed ¶
LoginAllowed reports whether an authenticated user may start a session.
Two tenant-level gates (docs/MULTI-TENANCY.md):
- SUSPEND: a disabled provider's users cannot log in (data intact) — in both modes. The supertenant cannot be suspended out of its own platform.
- MAINTENANCE MODE: multi-tenant OFF on an install that has grown tenants ⇒ only the supertenant provider's users may log in; tenants are locked out until the flag returns (reversible, nothing touched). A plain single-tenant install is unaffected — its only provider IS the supertenant.
One user-level gate:
- DISABLED ACCOUNT: users.enabled = false (migration 00022) refuses the session outright, in both modes, with files/quota/grants untouched. Checked first so it holds in a plain single-tenant install too.
Otherwise it fails toward availability: a NULL provider (bootstrap/legacy admin) or an unresolvable provider is allowed, so an operator is never locked out by a glitch. Only a resolvable, non-supertenant tenant is ever refused.
func LoginHostFrom ¶
LoginHostFrom returns the stamped host, or "".
func Middleware ¶
Middleware tries each enabled auth Driver in order. The first one that returns a non-nil user wins; subsequent drivers are not consulted.
On failure with required=true, a 401 JSON error is written and the downstream handler is NOT called. With required=false, the request proceeds with no user attached (useful for public viewer endpoints).
func MiddlewareWithToken ¶
MiddlewareWithToken authenticates EITHER via an API token (X-Filex-Token / Bearer) OR, failing that, the regular user-session driver chain. It powers the /api/files surface so a host app can proxy with a root-confined API token (see package confine) while the native admin panel keeps using its cookie/JWT session. An API-token bearer and a session JWT never collide: the token's sha256 simply won't match a JWT, so we fall through cleanly.
func NetReason ¶
NetReason classifies a connection error into the reasons the panel has words for: refused, timeout, dns, tls, or other.
func ProbeOKAll ¶
func ProbeOKAll(checks []ProbeCheck) bool
ProbeOKAll reports whether a probe passed: nothing failed and something was actually checked.
func ProvisionUser ¶
func ProvisionUser(ctx context.Context, store ProvisionStore, h TenantHoming, driver, email, role string) (*model.User, error)
ProvisionUser creates `email` and homes it in the tenant this login arrived for. `driver` names the caller, for the log line an operator will need when a directory user cannot sign in.
The three beats are the ones the invite path established: create; home; and on a failure to home, DELETE the row rather than leave a half-created supertenant account behind.
func RefuseVerb ¶ added in v0.49.0
func RefuseVerb(w http.ResponseWriter, verb string)
RefuseVerb writes the refusal a token without verb gets — the same body RequireScope has always answered on /api/ai, so a client reads one message whichever door it knocked on.
func RequireAdmin ¶
RequireAdmin denies with 403 a caller that may not administer: a non-admin account, or — when the request was authenticated by an API token — a token that does not grant the admin scope or is confined to a folder (see CallerMayAdminister). A signed-in administrator's session is judged by the account alone, as it always was.
⚠ It can only judge a token it can see, so the route group must attach the token to the context: MiddlewareWithToken does, and so does Middleware since the api-token driver reports its token to the chain (TokenAuthenticator).
func RequireAdminToken ¶
RequireAdminToken is the gate for the token-only admin surface (/api/ai/admin), where the token's scope — not the account's role — is what authorizes (the handlers there elevate the bound principal). It replaces RequireScope("admin") so a confined token is refused too. Must run after APITokenMiddleware.
func RequireScope ¶
RequireScope rejects requests whose token does not grant `scope`. A token grants only what its list names; an empty list grants nothing. Must run after APITokenMiddleware.
func RequireVerb ¶ added in v0.49.0
RequireVerb is RequireScope for the routes that accept BOTH a session and a token (MiddlewareWithToken): a session passes, a token must hold verb.
⚠ RequireScope refuses a request with no token at all, which is right on the token-only /api/ai surface and wrong here — it would lock the web explorer out of its own routes.
func ScopeForUser ¶
ScopeForUser resolves a user's tenant scope. Callers that authenticate outside the middleware chain — /dav does its own Basic auth — use this to attach the same scope the HTTP middleware would have.
ALWAYS returns a non-nil scope so the scoped store filters. A user whose provider is missing or unknown gets tenant.DenyAll (sees nothing) — fail closed, never a silent fall-through to "see everything".
func SetAuditTarget ¶
SetAuditTarget names the thing the request acted on, for the audit row the middleware writes: id fills target_id when the route did not carry one, name is stored as metadata["target_name"].
⚠⚠ Why: the Panel and the Audit page printed the KIND of thing and nothing else — "Kullanıcı: oluşturuldu — Kullanıcı", "Depo: oluşturuldu — Depo" (release-candidate sweep, 2026-09-21) — because a create's URL has no id and the middleware never reads bodies. The handler knows what it made; this is how it says so. The name is kept because it is what a reader wants AFTER the thing is gone ("which user was deleted?"). A name here is a label — an e-mail, a storage name, a path — never a secret.
func SetEnabled ¶
func SetEnabled(drivers []Driver)
SetEnabled stores the active driver chain (ordered) for the middleware.
func SetPermissionStore ¶ added in v0.49.0
SetPermissionStore gives the session middleware the store it resolves permission-rule settings from. Unset (tests), Require 2FA is not enforced at the session layer.
func TenantResolver ¶
TenantResolver derives the request's tenant (provider) scope from the authenticated user's provider_id and stashes it in the context for the scoped store and storage confinement to read. It is a **no-op when multi-tenant mode is off** — no scope is set, and callers treat the absence as "unscoped", so single-tenant behaviour is byte-unchanged. Mount it AFTER the auth middleware so the user is already resolved.
The user's own provider_id — not the request Host — is the source of truth for scoping: a user belongs to exactly one tenant regardless of which host they reach. (Host binding drives which OIDC realm authenticates a *login*; that is the login layer's concern, not request scoping.)
A supertenant scope carries IsSupertenant + no StorageIDs; it is confine-exempt and cross-tenant (see docs/MULTI-TENANCY.md).
func TokenAllows ¶ added in v0.49.0
TokenAllows reports whether the request may use verb: always for a request with no API token on its context, and for a token when its list names verb.
func TokenFrom ¶
TokenFrom returns the API token from ctx, nil if the request was not authenticated by an API token (e.g. a cookie session).
func TokenIsConfined ¶
TokenIsConfined reports whether tok carries a `root:` confinement scope.
⚠ Syntactic on purpose: ANY `root:` entry counts, well-formed or not. A scope the confinement parser cannot read (`root:projects`, no storage) would otherwise make the token look unconfined here — the one direction a mistake in an authorization check must not fall.
func TokenMayAdminister ¶
TokenMayAdminister reports whether a token is an operator credential: it grants the admin scope and is not confined. It says nothing about the account the token is bound to — see CallerMayAdminister for that.
func TokenMayBeUsed ¶ added in v0.49.0
TokenMayBeUsed reports whether u may authenticate with tok. A resolution error refuses — a credential that cannot be judged is not accepted.
func TokenPermission ¶ added in v0.49.0
TokenPermission is the permission using tok needs.
func TokenUserFrom ¶
TokenUserFrom returns the identity a token-authenticated request acts under ("" for cookie sessions). Set by the token middlewares alongside WithToken.
func TwoFactorPending ¶ added in v0.49.0
TwoFactorPending reports whether u is bound by a Require 2FA rule and has not enrolled.
func TwoFactorPendingAllowed ¶ added in v0.49.0
TwoFactorPendingAllowed reports whether a pending session may reach path.
func WithLoginHost ¶
WithLoginHost stamps the Host of the HTTP request that started a login onto the context.
⚠ It exists because auth.LoginDriver.Login takes only a ctx — no *http.Request — so a driver in the login chain cannot see the host by itself. Widening the interface would touch every driver and every protocol caller for the benefit of one; the context carries it instead, and a login that arrives without one (a protocol login) simply has no host, which is the truth.
func WithRequestLoginHost ¶
WithRequestLoginHost is WithLoginHost for an *http.Request.
func WithToken ¶
WithToken stores the matched API token on ctx, and notes its id (never the secret) on the request's access-log holder, like WithUser does the account.
func WithTokenUser ¶
WithTokenUser stores the resolved token username on ctx.
Types ¶
type AuditDetail ¶
type AuditDetail struct {
// contains filtered or unexported fields
}
AuditDetail is what a handler adds to the audit row the middleware writes for its request: the facts only the handler knows (which fields changed, before and after) — so a change is ONE row that says what it did, not a bare "auth_provider.update".
⚠ Names and flags only. Nothing a handler puts here may be a secret: the audit log is read by every administrator and exported.
func WithAuditDetail ¶
func WithAuditDetail(ctx context.Context) (context.Context, *AuditDetail)
WithAuditDetail returns a context carrying an empty detail holder.
func (*AuditDetail) ApplyTarget ¶
func (d *AuditDetail) ApplyTarget(targetID string, meta map[string]interface{}) (string, map[string]interface{})
ApplyTarget folds SetAuditTarget's answer into a row: the id only where the route gave none, the name into meta. Nil-safe.
func (*AuditDetail) Into ¶
func (d *AuditDetail) Into(meta map[string]interface{}) map[string]interface{}
Into merges the recorded facts into meta (allocating it when needed).
type Capabilities ¶
type Capabilities struct {
SignIn bool `json:"sign_in"`
Logout bool `json:"logout"`
ChangePassword bool `json:"change_password"`
Register bool `json:"register"`
}
Capabilities advertises what an auth driver supports — used by the UI to decide whether to render Login / Register / ChangePassword buttons.
type Driver ¶
type Driver interface {
Name() string
Init(ctx context.Context, cfg map[string]any) error
Authenticate(r *http.Request) (*model.User, error)
Capabilities() Capabilities
}
Driver is the abstract authentication backend.
Authenticate is called by the auth middleware for every protected request and must be cheap. Drivers should NOT block on network IO during Authenticate — heavy work belongs in Init or in callbacks.
type Factory ¶
type Factory func() Driver
Factory builds a fresh Driver instance — invoked once per server start.
type LoginChain ¶
type LoginChain struct {
// contains filtered or unexported fields
}
LoginChain tries a password against several login drivers in turn.
Why this type exists ¶
Before it, the login handler held ONE LoginDriver and the server bootstrap only ever assigned the `local` driver to it. A directory driver could be configured, initialised, and listed in the boot banner while its Login method was unreachable from any code path — `FILEX_AUTH_DRIVERS=local,ldap` produced a server that said "Auth: ldap, local" and answered every directory account with 401 in ~350us, which is less than one LDAPS round trip. The docs meanwhile described exactly the behaviour this type implements ("filex tries each enabled driver in order"), so the gap read as a directory misconfiguration to everyone who hit it.
Order is the contract ¶
Drivers are tried in the order the operator listed them in `auth.drivers` / FILEX_AUTH_DRIVERS. Keeping `local` first matters: it is a bcrypt compare against a row that is already local, so the built-in admin@local account and every break-glass password stay answerable when the directory is unreachable. A directory driver placed first would put a network round trip in front of every local login and, on an unreachable directory, in front of the one login that is supposed to still work.
func NewLoginChain ¶
func NewLoginChain(drivers ...LoginDriver) *LoginChain
NewLoginChain returns a chain over drivers, in order. Nil drivers are dropped so a caller can pass an optional driver without a nil check.
func (*LoginChain) Len ¶
func (c *LoginChain) Len() int
Len reports how many drivers the chain will try. Used by the bootstrap to avoid wrapping a single driver in a chain for nothing.
func (*LoginChain) Login ¶
func (c *LoginChain) Login(ctx context.Context, identifier, password string) (*model.User, string, error)
Login tries each driver in order and returns the first success.
A driver that answers ErrUnauthorized has judged the credentials and said no; the chain moves on, because "not my user" and "wrong password" are the same answer by design (no account enumeration). Any OTHER error means the driver could not judge at all — an unreachable directory, a TLS failure, a bad service-account bind — and that is NOT swallowed: it is logged with the driver name and returned when no later driver succeeds, so an operator reading the log can tell "wrong password" from "the directory is down".
func (*LoginChain) Logout ¶
func (c *LoginChain) Logout(ctx context.Context, token string) error
Logout revokes the session on every member.
Every login driver mints its session in the same sessions table (that is what makes one cookie work regardless of which driver authenticated), so revoking on all of them is idempotent rather than wasteful — and it stays correct if a future driver keeps state of its own. The first error is reported; the remaining drivers still run, because a half-revoked session is the one outcome worth avoiding.
func (*LoginChain) Name ¶
func (c *LoginChain) Name() string
Name reports the chain and its members, so a boot line or a log entry names the drivers a password will actually be tried against — the thing that was impossible to see from the outside before.
type LoginDriver ¶
type LoginDriver interface {
Login(ctx context.Context, email, password string) (*model.User, string, error) // user, sessionToken, err
Logout(ctx context.Context, token string) error
}
LoginDriver is an optional capability — drivers that accept username + password directly (i.e. local) implement it.
type OIDCDriver ¶
type OIDCDriver interface {
StartFlow(w http.ResponseWriter, r *http.Request) error
HandleCallback(w http.ResponseWriter, r *http.Request) (*model.User, string, error)
}
OIDCDriver is an optional capability — drivers that perform browser redirects to an external IdP implement it.
type OIDCLogoutDriver ¶
type OIDCLogoutDriver interface {
EndSessionURL(r *http.Request, idToken, postLogoutRedirect string) string
}
OIDCLogoutDriver is an optional capability of an OIDCDriver: RP-initiated logout (OpenID Connect RP-Initiated Logout 1.0). EndSessionURL returns where to send the browser so the IdP ends its own session too — idToken is the one kept for the session being signed out — or "" to keep sign-out local.
type ProbeCheck ¶
type ProbeCheck struct {
ID string `json:"id"`
Status string `json:"status"`
Params map[string]string `json:"params,omitempty"`
}
ProbeCheck is one step of a provider test. ID names the step (the panel words it in the reader's language); Params carries what the sentence needs — a host, a field list, a reason, the technical detail.
func Check ¶
func Check(id, status string, kv ...string) ProbeCheck
Check builds a ProbeCheck from key/value pairs.
type Prober ¶
type Prober interface {
Probe(ctx context.Context, cfg map[string]any, r *http.Request) []ProbeCheck
}
Prober is a driver that can test a configuration without anyone signing in. cfg is the configuration to test (the form's values over the stored ones), not the running driver's; r is the administrator's own request, which the proxy-header driver examines.
type ProvisionStore ¶
type ProvisionStore interface {
CreateUser(ctx context.Context, email, passwordHash, role, locale, tz string) (*model.User, error)
DeleteUser(ctx context.Context, id int64) error
GetUser(ctx context.Context, id int64) (*model.User, error)
SetUserProvider(ctx context.Context, userID, providerID int64, oidcSubject string) error
GetProviderByHost(ctx context.Context, host string) (*model.Provider, error)
GetProviderBySlug(ctx context.Context, slug string) (*model.Provider, error)
}
ProvisionStore is the slice of db.Store just-in-time provisioning needs.
type TenantHoming ¶
type TenantHoming struct {
// MultiTenant mirrors cfg.MultiTenant. False = do nothing at all.
MultiTenant bool
// Pin is an operator-declared provider SLUG, used when the login carries no
// host that maps to a tenant.
//
// ⚠ It exists for the logins that structurally have no Host: SFTP, FTPS and
// NFS present a password on a socket, not an HTTP request. Without it, a
// multi-tenant install simply cannot provision a directory user over those
// protocols — which is a defensible default (the account still works the
// moment it has logged in through the web once) but a bad surprise, so the
// operator gets a way to say it out loud.
Pin string
}
TenantHoming is a driver's policy for where its JIT accounts land.
type TokenAuthenticator ¶
type TokenAuthenticator interface {
AuthenticateToken(r *http.Request) (*model.User, *model.APIToken, error)
}
TokenAuthenticator is implemented by a Driver whose credential IS an API token (drivers/apitoken). The chain calls it instead of Authenticate so the matched token reaches the request context together with the user.
⚠ Why this exists: the api-token driver is always enabled, so a token authenticates on any route group built on Middleware — and the driver used to hand back the user and drop the token. Every scope check downstream then saw a request with no token at all and judged it by the account's role, which made a read-only token minted on an administrator's account a full administrator credential on the admin routes.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
drivers
|
|
|
apitoken
Package apitoken implements bearer-token authentication for non-interactive callers: AI agents, the work.example.com FilexClient, and the embedded MCP server.
|
Package apitoken implements bearer-token authentication for non-interactive callers: AI agents, the work.example.com FilexClient, and the embedded MCP server. |
|
ldap
Package ldap implements simple-bind LDAP/Active Directory authentication.
|
Package ldap implements simple-bind LDAP/Active Directory authentication. |
|
local
Package local implements username + password authentication backed by the users table.
|
Package local implements username + password authentication backed by the users table. |
|
multioidc
Package multioidc dispatches OIDC flows to per-tenant IdP realms (docs/MULTI-TENANCY.md §5,§7).
|
Package multioidc dispatches OIDC flows to per-tenant IdP realms (docs/MULTI-TENANCY.md §5,§7). |
|
oidc
Package oidc implements OpenID Connect authentication.
|
Package oidc implements OpenID Connect authentication. |
|
proxyheader
Package proxyheader implements authentication via headers injected by a trusted upstream reverse proxy (nginx, Caddy, oauth2-proxy, Cloudflare Access, Authelia, …).
|
Package proxyheader implements authentication via headers injected by a trusted upstream reverse proxy (nginx, Caddy, oauth2-proxy, Cloudflare Access, Authelia, …). |