Skip to main content
When you set access_mode = "accounts", floo provides a hosted OAuth flow powered by WorkOS. Your app’s users can sign in with email, Google, GitHub, and more — no auth infrastructure to build.

What happens when you enable it

  1. You set access_mode = "accounts" and [auth] redirect_uris in your config
  2. You deploy with floo deploy
  3. Floo automatically provisions the auth endpoints for your app
No separate WorkOS account is needed — floo manages this for you. The auth endpoints are live as soon as the deploy completes. The app_id in the OAuth URLs below is your app’s UUID, which you can get with floo apps list --json.

Prerequisites

  • your plan is Pro or above
  • your app is deployed on floo
  • you know the callback URL(s) your app will handle

1. Configure your app

Set the access mode and register your OAuth callback URLs in floo.app.toml:
[app]
name = "my-app"
access_mode = "accounts"

[auth]
redirect_uris = [
  "http://localhost:3000/callback",
  "https://my-app.on.getfloo.com/callback"
]
Then deploy:
floo deploy

2. Get your app ID

You will need your app’s UUID for the auth endpoints:
floo apps list --json | jq '.data.apps[] | select(.name == "my-app") | .id'

3. Integrate the OAuth flow

All auth endpoints are under https://api.getfloo.com/v1/auth/apps/{app_id}.

Start login

Redirect your user’s browser to:
GET /v1/auth/apps/{app_id}/authorize?redirect_uri=https://my-app.com/callback
The redirect_uri must match one of the URIs registered in your [auth] config.

Handle the callback

After the user authenticates, floo redirects back to your redirect_uri with a one-time exchange code:
https://my-app.com/callback?code=<exchange_code>

Exchange code for tokens

From your backend, exchange the code for an access token and refresh token:
curl -X POST https://api.getfloo.com/v1/auth/apps/{app_id}/token \
  -H "Content-Type: application/json" \
  -d '{"grant_type": "authorization_code", "code": "<exchange_code>"}'
Response:
{
  "access_token": "<jwt>",
  "refresh_token": "<opaque_token>",
  "expires_in": 3600,
  "user": {
    "id": "<uuid>",
    "email": "user@example.com",
    "name": "Jane Doe",
    "avatar_url": "https://..."
  }
}

Verify the JWT

The access_token is an RS256-signed JWT. You can verify it locally using the public keys:
GET /v1/auth/apps/{app_id}/.well-known/jwks.json
JWT claims:
ClaimDescription
subapp user ID (UUID)
emailuser’s email address
nameuser’s display name
isshttps://auth.getfloo.com
audyour app ID
iatissued at
expexpiration

Refresh tokens

When the access token expires, use the refresh token to get a new one:
curl -X POST https://api.getfloo.com/v1/auth/apps/{app_id}/token \
  -H "Content-Type: application/json" \
  -d '{"grant_type": "refresh", "refresh_token": "<refresh_token>"}'
Refresh tokens are single-use — each refresh returns a new refresh token (rotation).

Logout

Revoke the refresh token when the user logs out:
curl -X POST https://api.getfloo.com/v1/auth/apps/{app_id}/session/logout \
  -H "Content-Type: application/json" \
  -d '{"refresh_token": "<refresh_token>"}'

Convenience endpoint

If you don’t want to decode the JWT yourself, use the session endpoint:
curl https://api.getfloo.com/v1/auth/apps/{app_id}/session/me \
  -H "Authorization: Bearer <access_token>"
Returns the authenticated user’s info.

Access modes

ModeDescriptionPlanBest for
publicNo auth, anyone can accessAllMarketing sites, open APIs
passwordShared app passwordPro+Private demos, client previews
accountsPer-user auth via hosted OAuthPro+Apps with named end users
ssoEnterprise SSO via SAML/OIDCEnterpriseEnterprise apps

Password-protected apps

floo apps password my-app

Environment overrides

Override access mode per environment:
[app]
name = "my-app"
access_mode = "accounts"

[environments.dev]
access_mode = "public"
Resolution order: [environments.dev].access_mode wins over [app].access_mode.

Config File Spec

Full reference for all config fields and precedence.

Team Access

Org membership, invites, and permissions.