---
title: "Auth Flow Overview"
description: "Which teenybase auth flow to use: email and password, OAuth redirect, Google One Tap or login-token, and cookie auth versus bearer tokens."
url: https://teenybase.com/docs/reference/auth-flows
last_updated: 2026-10-26
---

> Documentation index: https://teenybase.com/llms.txt lists every teenybase docs page with a link to its Markdown version. All docs in one file: https://teenybase.com/llms-full.txt

# Auth Flow Overview

This is a reference page. If you already know which auth flow you need, go directly to the recipe:

- [Email/password](https://teenybase.com/docs/guides/frontend) (the default - see Connect Your Frontend)
- [Google Sign In (redirect)](https://teenybase.com/docs/guides/google-oauth-custom)
- [Google One Tap / SPA](https://teenybase.com/docs/guides/google-oauth-onetap)
- [Email verification & password reset](https://teenybase.com/docs/guides/email-flows)

Teenybase supports several auth setups. Pick one that fits your app and stick with it.

> **Using a coding agent?** Paste this prompt:
>
> Choose the simplest teenybase auth flow for this app. Tell me whether I should use email/password, OAuth redirect, Google One Tap, or login-token, and show the exact config and endpoint calls for that choice.

## Not sure? Start here

Use **email/password with bearer tokens** by default. You build your own login screens and call the JSON auth endpoints from `fetch`. The default `npx teenybase create` scaffold already wires this up.

For copy-paste client code, see [Connect Your Frontend](https://teenybase.com/docs/guides/frontend).

## Quick decision guide

### Use email/password when

- you are building your own frontend
- you want the fewest moving parts
- you are okay storing bearer tokens in the app (or setting your own cookie from an SSR layer)

### Use OAuth redirect when

- you want a "Continue with Google" button on your own frontend
- you want the browser to come back to your app after login
- you want cookie auth, not manual token storage

### Use Google One Tap when

- your frontend is a SPA
- Google gives you the credential in the browser
- you want to POST that credential to teenybase

### Use `login-token` when

- another auth system already gives you a JWT
- you want teenybase to trust that issuer
- you do not want teenybase to be the primary identity provider

## Flow comparison

| Flow | Best for | What you configure | What the frontend handles |
|---|---|---|---|
| Email/password | Most custom apps | `users` table + `auth` extension | builds login UI, stores `token` + `refresh_token` |
| OAuth redirect | Custom frontend + Google button | `authProviders` + `authCookie` | redirects the browser, reads `authCookie` |
| Google One Tap | SPA login | Google provider in `authProviders` | sends the Google credential |
| `login-token` | Auth0, Firebase, Supabase, custom JWT | trusted `authProviders` config | sends bearer token to teenybase |

## 1. Email/password

This is the safest default.

The scaffolded project already gives you:

- a `users` table
- an `auth` extension
- row-level rules on the users table
- JSON endpoints for sign-up, login, refresh, and logout

You build your own login, sign-up, profile, and password-reset screens and call the JSON endpoints below — your frontend owns the visual layer.

### The default sign-up body

```json
{
  "username": "alice",
  "email": "alice@example.com",
  "password": "secret123",
  "passwordConfirm": "secret123",
  "name": "Alice"
}
```

### The default login body

```json
{
  "identity": "alice@example.com",
  "password": "secret123"
}
```

`identity` accepts either email or username.

### The main endpoints

```text
POST /api/v1/table/users/auth/sign-up
POST /api/v1/table/users/auth/login-password
POST /api/v1/table/users/auth/refresh-token
POST /api/v1/table/users/auth/change-password
POST /api/v1/table/users/auth/logout
```

For password reset and email verification (which require an `email` config), there are four more JSON endpoints:

```text
POST /api/v1/table/users/auth/request-password-reset
POST /api/v1/table/users/auth/confirm-password-reset
POST /api/v1/table/users/auth/request-verification
POST /api/v1/table/users/auth/confirm-verification
```

The reset and verification emails embed `{{APP_URL}}/reset-password/{{TOKEN}}` and `{{APP_URL}}/verify-email/{{TOKEN}}` links by default. Your frontend hosts those routes, extracts the token, and calls the matching `confirm-*` endpoint.

### Frontend wiring

The full copy-paste fetch client lives in [Connect Your Frontend](https://teenybase.com/docs/guides/frontend). For password reset and verification end to end, see [Email Verification & Password Reset](https://teenybase.com/docs/guides/email-flows).

## 2. OAuth redirect

Use this when your product wants a normal "Continue with Google" button and then a redirect back into your app.

### Minimal config

```ts
import {DatabaseSettings} from 'teenybase'

export default {
  appUrl: 'https://myapp.com',
  jwtSecret: '$JWT_SECRET',
  authCookie: { name: 'teeny_auth' },
  authProviders: [
    {
      name: 'google',
      clientId: '$GOOGLE_CLIENT_ID',
      clientSecret: '$GOOGLE_CLIENT_SECRET',
      redirectUrl: '/dashboard',
    },
  ],
  tables: [
    // your tables here
  ],
} satisfies DatabaseSettings
```

### Start the flow

```text
GET /api/v1/table/users/auth/oauth/google
```

You can also override the post-login redirect at request time:

```text
GET /api/v1/table/users/auth/oauth/google?redirect=/settings
```

Important:

- redirect flow needs `authCookie`
- the provider callback URL must be registered in Google Cloud Console
- redirect targets are checked against `appUrl` and `allowedRedirectUrls`

For the full step-by-step setup, see [Google Sign In (Custom Frontend)](https://teenybase.com/docs/guides/google-oauth-custom).

## 3. Google One Tap

Use this when Google gives you the credential in the browser and you want to hand it to teenybase.

### Minimal config

```ts
authProviders: [
  {
    name: 'google',
    clientId: '$GOOGLE_CLIENT_ID',
  },
]
```

### Browser HTML flow

```html
<script src="https://accounts.google.com/gsi/client" async></script>
<div id="g_id_onload"
  data-client_id="YOUR_CLIENT_ID"
  data-login_uri="http://localhost:8787/api/v1/table/users/auth/google-login"
  data-auto_prompt="true">
</div>
```

That endpoint expects:

```text
Content-Type: application/x-www-form-urlencoded
credential=<GOOGLE_ID_TOKEN>
g_csrf_token=<CSRF_TOKEN>
```

If `authCookie` is configured, `google-login` also sets the auth cookie. See [Google One Tap / SPA](https://teenybase.com/docs/guides/google-oauth-onetap) for the full setup.

## 4. `login-token`

Use this when another provider already gave you a JWT and you want teenybase to exchange that into a teenybase session.

```js
const res = await fetch('http://localhost:8787/api/v1/table/users/auth/login-token', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${externalJwt}`,
  },
})
```

This only works if `authProviders` is configured to trust that token issuer.

This is usually the right choice only if you already have Auth0, Firebase, Supabase, or another identity system in place.

## Cookie auth vs bearer tokens

This is the part that matters most for product behavior.

### Bearer tokens

Use bearer tokens when your frontend owns the auth logic. This is the default for SPAs, mobile apps, and any project that builds its own login screens.

- store `token` and `refresh_token`
- send `Authorization: Bearer <token>` on protected requests
- call `refresh-token` when needed

### Cookie auth

Use cookie auth when the browser should own the session.

- OAuth redirect expects this model
- Google One Tap can also set the cookie when configured
- SSR apps usually prefer this model — your server layer sets the cookie itself using the token returned by teenybase

### Which endpoints set cookies?

These custom JSON API calls do not set the cookie for your frontend:

```text
POST /api/v1/table/users/auth/sign-up
POST /api/v1/table/users/auth/login-password
POST /api/v1/table/users/auth/refresh-token
```

These browser flows do set the cookie when `authCookie` is configured:

```text
GET  /api/v1/table/users/auth/oauth/:provider
GET  /api/v1/table/users/auth/oauth/:provider/callback
POST /api/v1/table/users/auth/google-login
```

These logout routes do different things:

```text
POST /api/v1/table/users/auth/logout   # invalidate session and clear cookie
POST /api/v1/auth/logout               # clear cookie only
```

## Scaffold defaults

The default scaffold includes some fields your frontend needs to match:

- `authCookie: { name: 'teeny_auth' }` (used by OAuth callbacks and any SSR layer you add)
- `passwordConfirmSuffix: 'Confirm'` (sign-up and password-reset bodies must include `passwordConfirm`)
- `authFields`, which include `name`

So the default sign-up body needs all of these fields:

```json
{
  "username": "alice",
  "email": "alice@example.com",
  "password": "secret123",
  "passwordConfirm": "secret123",
  "name": "Alice"
}
```

## Summary

- **Build your own UI:** email/password with bearer tokens
- **Own frontend + Google button:** OAuth redirect
- **SPA + Google:** One Tap
- **Existing identity provider:** `login-token`
