Skip to main content

Service Auth Integration

This guide is for developers who deploy services on muvee and want to leverage muvee's built-in authentication. When a project has Require Auth enabled, muvee handles the entire OAuth login flow — your service receives authenticated requests with user identity already resolved.

Authentication, not authorization

muvee tells your service who the user is (authentication). It does not manage what each user is allowed to do — that is authorization, and it is your service's responsibility. For example, muvee will tell you "this request is from alice@company.com", but your service decides whether Alice can access a given resource.

Reading User Identity (Server-Side)

Every authenticated request that reaches your service includes the following headers, injected by Traefik after muvee's auth gateway verifies the user:

HeaderValueAlways present
X-Forwarded-UserEmail address (e.g. alice@company.com)Yes
X-Forwarded-User-NameDisplay name (e.g. Alice Zhang)When available from the OAuth provider
X-Forwarded-User-AvatarAvatar image URLWhen available from the OAuth provider
X-Forwarded-User-ProviderOAuth provider name (e.g. google, feishu)Yes

These headers are set by Traefik, not by the end user — they cannot be forged as long as your service is only reachable through Traefik. Your service does not need to parse cookies, validate JWTs, or talk to any OAuth provider.

# Python / Flask
email = request.headers.get("X-Forwarded-User")
name = request.headers.get("X-Forwarded-User-Name")
avatar = request.headers.get("X-Forwarded-User-Avatar")
provider = request.headers.get("X-Forwarded-User-Provider")
// Go
email := r.Header.Get("X-Forwarded-User")
name := r.Header.Get("X-Forwarded-User-Name")
avatar := r.Header.Get("X-Forwarded-User-Avatar")
provider := r.Header.Get("X-Forwarded-User-Provider")
// Node.js / Express
const email = req.headers["x-forwarded-user"];
const name = req.headers["x-forwarded-user-name"];
const avatar = req.headers["x-forwarded-user-avatar"];
const provider = req.headers["x-forwarded-user-provider"];

Reading User Identity (Client-Side)

Frontend JavaScript running in the browser cannot see these headers — they exist only between Traefik and your backend. To get user info from the frontend, call the auth gateway's userinfo endpoint:

const resp = await fetch("https://{BASE_DOMAIN}/_oauth/userinfo", {
credentials: "include",
});
if (resp.ok) {
const { email, name, avatar_url, provider } = await resp.json();
}

Returns 401 if the user is not authenticated.

Logout

To log the user out, redirect them to the auth gateway's logout endpoint:

https://{BASE_DOMAIN}/_oauth/logout?redirect=https://myapp.example.com

This clears the muvee_fwd_session cookie and redirects the user to the URL specified by redirect (defaults to / if omitted).

CLI / Headless Access (Device Flow)

For CLI tools or headless environments that need to access your auth-protected service without a browser session, muvee provides a Device Flow similar to gh auth login.

Step 1 — Request a device code

curl -X POST https://{BASE_DOMAIN}/_oauth/device/code
{
"device_code": "XXXXXXXXXXX...",
"user_code": "ABCD-1234",
"verification_uri": "https://{BASE_DOMAIN}/_oauth/device/activate",
"verification_uri_complete": "https://{BASE_DOMAIN}/_oauth/device/activate?code=ABCD-1234",
"expires_in": 600,
"interval": 5
}

Step 2 — Direct the user to authorize

Print a message with the complete URL so the user can click or copy-paste it directly:

Authorize this device: https://{BASE_DOMAIN}/_oauth/device/activate?code=ABCD-1234

Opening this URL takes the user to the OAuth login page. After login the browser shows a confirmation page, and the user can close the tab.

Step 3 — Poll for the token

curl -X POST https://{BASE_DOMAIN}/_oauth/device/token \
-H "Content-Type: application/json" \
-d '{"device_code": "XXXXXXXXXXX..."}'

Poll every interval seconds. While the user hasn't authorized yet, the response is:

{"error": "authorization_pending"}

Once authorized:

{
"access_token": "eyJhbGciOiJI...",
"token_type": "Bearer",
"expires_in": 7776000
}

Step 4 — Use the token

Pass the token as a Bearer header on every request:

curl -H "Authorization: Bearer eyJhbGciOiJI..." https://myapp.example.com/api/data

The token is valid for 90 days and works with all auth-protected projects under the same BASE_DOMAIN.