---
name: google-tasks-oauth-app
description: The Google Tasks API layer on top of the shared `google-cloud-console-oauth` skill — the two Tasks scopes and the tier they actually sit in (sensitive, not restricted, so no CASA assessment), the tasklists/tasks model and the undocumented `@default` alias, hierarchy and ordering that only the separate move call can write, the completed/hidden/deleted/assigned flags that silently drop tasks out of a list response, the documented quota and data caps, and why tasks appearing in Google Calendar does not mean you need a Calendar scope. Use when asked to get Google Tasks OAuth credentials, scope a Google Tasks app, judge what verification a Tasks integration needs, or explain why a Tasks sync is missing completed, hidden or assigned tasks. Read `google-cloud-console-oauth` first for the console mechanics; use the Drive, Ads or Business Profile skill when the product is not Tasks.
---

# Google Tasks OAuth2 App Registration

**This is the cheap Google review.** Tasks has exactly two scopes, neither is restricted, and a Tasks-only app needs
app verification but **no CASA security assessment and no annual re-assessment** — the cost that dominates the Drive
and Gmail skills is simply absent here. Registration is the base skill, unchanged.

What is left is small and worth reading anyway, because three things bite in production and none of them fail at
authorization: **completed and hidden tasks are missing from list responses unless you ask for them**, **hierarchy and
ordering are not writable fields**, and **the `@default` list alias everyone uses is not in Google's current docs**.

## Built on: `google-cloud-console-oauth`

**Read `google-cloud-console-oauth` first, then this file.** It owns all the console mechanics, and this file does not
repeat them:

- Choosing/creating the Cloud project, enabling the API, and who may administer it.
- Configuring the app on the Google Auth Platform (Branding, Audience, Data Access, Clients) and creating a **Web
  application** client — the only type that yields a usable client secret.
- Redirect-URI rules (exact matching, HTTPS-only, propagation delay) and the platform's per-data-center callback list.
- The generic scope model — declaring every scope on Data Access, the three tiers, `access_type=offline` +
  `prompt=consent` as the only way to get a refresh token — and the client secret being shown **once** at creation.
- `Testing` vs `In production` (including the seven-day refresh-token expiry), the 100-user caps, verification, and a
  Workspace admin's power to block the client or switch the service off entirely.

If you are reading only this file, you are missing all of the above.

## Tasks platform state (verified 2026-09-20 — re-verify before trusting)

- **There are exactly two scopes**, and the v1 discovery document (revision `20260915`) lists no others:
  `https://www.googleapis.com/auth/tasks` ("Create, edit, organize, and delete all your tasks") and
  `https://www.googleapis.com/auth/tasks.readonly` ("View your tasks").
- **Neither appears on Google's restricted-scope list.** That list is authoritative and enumerates Gmail, Drive, Fit,
  Chat, Data Portability, Photos Ambient and Health scopes — Tasks is not on it (§1).
- **API host `tasks.googleapis.com`, service path `/tasks/v1`.** Two resources only: `tasklists` (delete, get,
  insert, list, patch, update) and `tasks` (clear, delete, get, insert, list, move, patch, update).
- **There is no `watch` / push-notification method.** Nothing in the API delivers change events; any "webhook" over
  Tasks is polling that someone else built.
- **Documented quota: 50,000 queries per day**, courtesy limit, per project (§5).

If the API surface does not look like this, stop and report what you actually see.

## Inputs to collect before you start

The base skill lists the console inputs. Tasks adds only these:

| Input | Notes |
| --- | --- |
| **Read-only, or read-write?** | The whole scope decision. Note that *reordering and re-parenting are writes* (§3) |
| **Must completed / cleared / assigned tasks be visible?** | Changes the list calls, not the scopes (§4) |
| **User OAuth, or a service account with domain-wide delegation?** | Both work; they share a quota bucket differently (§5) |
| **Is "tasks on the calendar" in the requirement?** | Almost always means Tasks, not Calendar (§6) |

## Quick Start

1. Work the base skill's console steps, and **enable the Google Tasks API** on the project.
2. Pick one scope — `tasks.readonly` or `tasks` — and declare exactly that on Data Access (§1).
3. Expect **sensitive-scope verification**: justification plus a demo video, no security assessment (§1).
4. Decide the visibility flags the integration will send *before* anyone tests a sync (§4).
5. Finish the base skill's capture, round-trip and handoff steps, adding the checks in §7.

## 1. The two scopes and their tier

| Scope | Grants | Tier |
| --- | --- | --- |
| `https://www.googleapis.com/auth/tasks.readonly` | Read task lists and tasks | **Sensitive** |
| `https://www.googleapis.com/auth/tasks` | Everything, including `insert`, `patch`, `update`, `delete`, `move`, `clear` | **Sensitive** |

**Stated plainly: neither Tasks scope is restricted.** Verified against Google's restricted-scope list on 2026-09-20 —
Tasks does not appear on it. So a Tasks-only app faces brand verification and **sensitive**-scope review (a
per-scope justification and an unlisted demo video, which Google quotes at roughly 3–5 business days), and **not** the
CASA security assessment, its assurance levels, or the annual recertification. If someone has budgeted an external
assessment for a Tasks integration, they have budgeted for the wrong API.

Two caveats worth saying out loud:

- Google publishes an exhaustive **restricted** list but not an exhaustive **sensitive** list. "Not restricted" is the
  verifiable half; read the tier label off the console's Data Access picker for the final word before submitting.
- **The tier of the app is the tier of its most sensitive scope** (base skill). Tasks is cheap *on its own*. Bundle it
  with Gmail or Drive read scopes in the same project and the project is restricted — the Tasks half saves nothing.

There is no narrower alternative to choose between: no per-list scope, no "metadata only" variant, no app-private
equivalent of `drive.file`. The only lever is read-only versus read-write, and §3 decides that more often than people
expect.

## 2. The model: task lists, tasks, and `@default`

Two levels, and that is the entire hierarchy of containers:

- **Task lists** — `GET /users/@me/lists`. A user can have up to **2000 lists**; `maxResults` defaults to 1000 and
  caps at 1000, so one page usually holds everything, but the `nextPageToken` still has to be honoured.
- **Tasks** — `GET /lists/{tasklist}/tasks`, always scoped to one list. `maxResults` defaults to **20** and caps at
  **100**, which is the single most common cause of "the sync only found twenty tasks". Cursor pagination via
  `pageToken` / `nextPageToken`.

There is no cross-list task query. Anything resembling "all of the user's tasks" is a fan-out: list the lists, then
page each one. Budget the quota for that shape (§5).

> **`@default` is undocumented.** The `@default` task-list alias is used everywhere in the wild, but as of 2026-09-20
> the string appears **nowhere** in the Tasks REST reference or in the v1 discovery document. `@me` *is* documented, in
> the `users/@me/lists` path. Treat `@default` as an undocumented convenience: do not build a sync on it, and do not
> put it in a customer-facing configuration. Enumerate the lists and match on an identifier you were given.

## 3. Hierarchy and ordering: `parent`, `position`, and why `move` is its own call

A task carries `parent` (omitted for a top-level task) and `position` (a string compared **lexicographically** against
siblings — greater sorts later). Both are documented **output-only / read-only**.

That is the trap: **you cannot re-parent or reorder a task by writing `parent` or `position`.** Those fields on an
update are ignored, silently — the call succeeds and nothing moves.

- **Re-parent, reorder, or move between lists:** `POST /lists/{tasklist}/tasks/{task}/move`, with optional query
  parameters `parent`, `previous` (the new previous sibling; omit to place first) and `destinationTasklist`.
- **At creation only,** `insert` accepts `parent` and `previous` as query parameters, so a task can be born in place.
- **`move` requires the full `tasks` scope.** Reordering is a write. An integration that is "read-only except it keeps
  our ordering in sync" is a read-write integration, and needs the sensitive write scope (§1).

Documented edge cases on `move` — each an error, not a silent no-op: a `parent` or `previous` task must exist in the
list and **must not be hidden**; assigned and repeating tasks can neither have subtasks nor become subtasks; a task
that is both completed and hidden cannot be nested and can only be moved to position 0. Limit: **2,000 subtasks per
task**.

Two more read-only-field surprises while mapping: `due` records **date only** — the time portion is discarded on
write, and the time a task is scheduled for "isn't possible to read or write using the API" — and `hidden`, `links`,
`webViewLink` and `assignmentInfo` are all output-only.

## 4. The silent disappearances: completed, hidden, deleted, assigned

Four flags on `tasks.list` decide what comes back. Their defaults do not agree with each other, and every one of them
fails by *omission* — a 200 with a short list, never an error.

| Parameter | Default | What it costs you |
| --- | --- | --- |
| `showCompleted` | **true** | On by default, and still not enough on its own — see below |
| `showHidden` | **false** | The one that actually bites |
| `showDeleted` | **false** | Deleted tasks are tombstones, not gone (below) |
| `showAssigned` | **false** | Tasks assigned from Docs and Chat Spaces are absent by default |

**Completed tasks need both flags.** Google's own wording: `showHidden` must *also* be true to show tasks completed
in first-party clients — the web UI and the mobile apps. `showCompleted=true` alone is the default and is why a sync
looks correct in testing (where tasks were completed via the API) and loses history in production (where users
complete tasks in the Google UI).

**"Hidden" is what `clear` does.** `POST /lists/{tasklist}/clear` marks every completed task in the list `hidden`; the
`hidden` field means "this task was completed when the list was last cleared". So a user tidying their list does not
delete anything — it vanishes from your default list response and reappears the moment you send `showHidden=true`.
Combine that with §3: a hidden task cannot be used as a `parent` or `previous`, so a sync that re-orders after a clear
starts failing on tasks it can no longer even see.

**Deleted tasks are tombstones.** `showDeleted=true` returns tasks with `deleted: true`. For an incremental sync that
is the only way to learn a task was removed, since nothing in the API delivers change events (Tasks platform state). For a first full sync it is
noise. Pair it with `updatedMin` rather than sending it blindly.

The other list filters — `dueMin`/`dueMax`, `completedMin`/`completedMax`, `updatedMin` — are all optional RFC 3339
timestamps that default to *no* filtering.

**Data caps that read like quota errors:** up to **20,000 non-hidden tasks per list** and **100,000 tasks in total**
per user. A user at the per-list ceiling is a support conversation, not a retry.

## 5. Quotas

- **Documented:** a courtesy limit of **50,000 queries per day**, per project, adjustable through the Cloud console's
  Quotas page (approval not guaranteed, and large increases take longer).
- **Not documented in the Tasks docs:** any per-minute or per-user figure. Those limits exist and are real — they
  surface as **`403` with reason `rateLimitExceeded` or `userRateLimitExceeded`** — but the numbers are read off the
  project's Quotas page in the Cloud console, not from any published Tasks page. Do not quote a QPM figure you found
  in a blog post.
- **A `403` rate-limit is not an auth failure**, and this is the misdiagnosis to pre-empt: Google returns quota
  exhaustion with HTTP 403, the same status as a permission problem, so a naive client treats it as a broken token and
  re-authorizes in a loop. Map the rate-limit reasons to a 429-style back-off before you ship.
- **Service accounts share one bucket.** Google states explicitly that API calls by a service account "are considered
  to be using a single account". A domain-wide-delegation deployment therefore concentrates every impersonated user's
  traffic into one quota identity — the opposite of what the per-user flow does.
- The §2 fan-out is the quota risk: *lists × pages of 100* per full sync, per user. Do that arithmetic against 50,000
  before promising a polling interval.

## 6. Calendar overlap — which scope a reader actually needs

Google Tasks shows up inside Google Calendar (and in the Gmail, Chat, Drive and Docs side panels); Google's own help
page tells users to "access Tasks in Calendar in your browser". So requirements arrive written as "read the tasks on
the user's calendar", and the reflex is to reach for a Calendar scope. **That is wrong in both directions:**

- **A Calendar scope does not get you tasks.** The Calendar API's `eventType` enum is `birthday`, `default`,
  `focusTime`, `fromGmail`, `outOfOffice`, `workingLocation` — there is no task type, and the Events resource does not
  represent tasks at all. The Tasks API is the only documented programmatic path to a user's tasks.
- **A Tasks scope does not get you the calendar view.** Because `due` is date-only (§3), a task the user scheduled for
  a specific time renders on the Calendar grid at that time while the API can neither read nor write that time. If the
  requirement genuinely depends on time-of-day placement, say now that the API cannot supply it.

Practical consequence: an integration whose job is "the user's to-dos" should request **only** a Tasks scope. Adding
Calendar scopes to reach tasks buys nothing and widens the verification review for no capability.

One more shared-with-Calendar reality from the base skill: on work and school accounts an administrator controls
whether Tasks is available at all. Where the *service* is off, calls fail with `403 PERMISSION_DENIED` regardless of
how well the client is allowlisted — that is the customer's admin console, not your registration.

## Product fact — what the Tasks connector asks for

> **As of 2026-09-20, Unified.to's Google Tasks connector requests:**
>
> - **Read** (task lists and tasks): `https://www.googleapis.com/auth/tasks.readonly`
> - **Write** (task lists and tasks): `https://www.googleapis.com/auth/tasks`
> - **Login/identity only:** `openid`, `profile`, `email`
>
> Scopes are selected per object *and per direction*, so a read-only deployment declares `tasks.readonly` alone and
> never triggers the write scope. Remember §3 before choosing that: reordering and re-parenting are writes.
>
> Auth quirks worth confirming: the authorize request carries `access_type` and `prompt`, which is what makes a
> refresh token come back on a first *and* a repeat authorization (base skill); the code exchange and refresh are
> form-posted with the client secret in the body; tokens are sent as bearer. Alongside user OAuth the connector also
> supports a **Google service-account credential** path scoped to `.../auth/tasks` — the domain-wide-delegation route,
> with the shared quota bucket noted in §5. Paging uses `pageToken`/`nextPageToken` with `maxResults` capped at 100,
> matching §2. Provider `403`s carrying a rate-limit reason are remapped to a 429-style back-off rather than treated
> as an auth failure, per §5. Unlike the Drive connector, this one is not flagged as needing a custom callback domain.
>
> Scope sets and auth behaviour change. This note is **dated, not live** — confirm with the connector's owner before
> submitting anything to Google.

## 7. Tasks-specific end-to-end checks

On top of the base skill's authorize → refresh round trip:

1. List the user's task lists, then list tasks in one of them, and confirm the Tasks API is enabled and returning data.
2. Re-run the task list with **`showCompleted=true&showHidden=true`** and compare counts against the first call. If
   they differ, your default sync is losing completed history (§4) — verify against a task completed in the Google UI,
   not one completed through the API.
3. Create more than 20 tasks and page the list. Anything that stops at 20 has not read `maxResults` (§2).
4. If ordering or subtasks matter, attempt a re-parent by writing `parent` on an update, confirm it silently does
   nothing, then do it through `move` (§3). This is the check people skip.
5. Run `clear` on a scratch list and confirm the cleared tasks reappear only with `showHidden=true` (§4).
6. Confirm the granted `scope` in the token response matches what was requested — granular consent lets a user drop a
   scope, and a write-scope drop fails later at `move`/`insert`, not at consent.

| Symptom | Cause |
| --- | --- |
| Every Tasks call fails although scopes look right | Google Tasks API not enabled on the project, or the admin has Tasks off for the account (§6) |
| The sync finds exactly 20 tasks per list | `maxResults` default (§2) |
| Completed tasks missing, or history disappears over time | `showHidden` not sent — the user cleared the list (§4) |
| Deletions never propagate | `showDeleted` not sent; no push notifications exist to carry them (§4) |
| Tasks assigned from Docs or Chat Spaces never appear | `showAssigned` defaults to false (§4) |
| Reordering / re-parenting "succeeds" and changes nothing | `parent` and `position` are read-only; use `move` (§3) |
| `move` fails on a task that exists | Target `parent`/`previous` is hidden, or the task is assigned/repeating (§3) |
| Time-of-day on a task is always lost | `due` is date-only by design (§3) |
| `403` with `rateLimitExceeded` and a re-auth loop | Quota, not authorization — back off (§5) |
| A Calendar-scoped app cannot see the user's tasks | Tasks are not Calendar events (§6) |

## Stop and ask

Beyond the base skill's list, hand back to a human when:

- Someone has scheduled or budgeted a **CASA security assessment** for a Tasks-only app — check §1 before anyone pays.
- Tasks scopes are about to be added to a project that already holds **Gmail or Drive restricted scopes**; that is a
  verification-scope decision, not a checkbox (§1).
- The requirement depends on **time-of-day** task scheduling, **cross-list queries**, or **change notifications** —
  none of which the API provides (§2, §3, §6).
- A design relies on **`@default`** as a stable list identifier (§2).
- A **service-account / domain-wide-delegation** deployment is proposed at volume, and nobody has done the shared-quota
  arithmetic (§5).
- The API surface or scope list does not match the **Tasks platform state** section above.

## References

Tasks-specific only; the base skill carries the generic Google OAuth references. Verified to resolve on 2026-09-20.

- Google Tasks API reference overview — https://developers.google.com/workspace/tasks/reference/rest
- Task resource (`parent`, `position`, `hidden`, `deleted`, `due`, `assignmentInfo`) — https://developers.google.com/workspace/tasks/reference/rest/v1/tasks
- `tasks.list` (`showCompleted`, `showHidden`, `showDeleted`, `showAssigned`, `maxResults`) — https://developers.google.com/workspace/tasks/reference/rest/v1/tasks/list
- `tasks.move` (`parent`, `previous`, `destinationTasklist`, subtask limit) — https://developers.google.com/workspace/tasks/reference/rest/v1/tasks/move
- `tasks.insert` (`parent` / `previous` at creation, per-list task limits) — https://developers.google.com/workspace/tasks/reference/rest/v1/tasks/insert
- `tasks.clear` (what "hidden" means) — https://developers.google.com/workspace/tasks/reference/rest/v1/tasks/clear
- `tasklists.list` (2000-list limit, `users/@me/lists`) — https://developers.google.com/workspace/tasks/reference/rest/v1/tasklists/list
- Google Tasks API quotas and usage limits (50,000 queries/day; service accounts count as one account) — https://developers.google.com/workspace/tasks/limits
- Google Tasks API quickstart (a working scope declaration) — https://developers.google.com/workspace/tasks/quickstart/python
- Learn about Google Tasks (surfacing in Calendar and side panels; admin controls access) — https://support.google.com/tasks/answer/7675772?hl=en
- Google Calendar API Events reference (`eventType` has no task value) — https://developers.google.com/workspace/calendar/api/v3/reference/events
