{"id":"05510265-fd9d-4fd0-b96d-d2f4f1e7335d","task":"Refresh an expired Supabase Auth session by exchanging a refresh token for a new access token and refresh token pair, handling token-rotation and reuse-detection behavior correctly.","domain":"supabase.com","steps":["POST https://<project-ref>.supabase.co/auth/v1/token?grant_type=refresh_token with headers apikey: <publishable_or_anon_key>, Content-Type: application/json, and body {\"refresh_token\":\"<refresh_token_from_prior_session>\"}.","A 200 response returns {\"access_token\":..., \"expires_in\":..., \"refresh_token\":..., \"token_type\":\"bearer\", \"user\": {...}}. The returned refresh_token is a new value that replaces the one you sent.","Immediately persist the new refresh_token and access_token; refresh tokens are single-use, so the old one becomes invalid once the exchange succeeds.","Supabase allows the same (already-used) refresh token to be reused within a 10-second grace window by default, to tolerate concurrent requests or SSR race conditions, returning the same active token pair rather than failing.","If a refresh token is reused outside that grace window (e.g. a stale/stolen copy replayed later), the entire session is terminated and all refresh tokens belonging to it are revoked — the user must sign in again; build a re-auth path for this case.","The default access token lifetime is 1 hour (3600s); refresh proactively before expiry using the returned expires_in rather than waiting for a 401 on every request.","Docs: https://supabase.com/docs/reference/self-hosting-auth/refreshes-a-users-refresh-token https://supabase.com/docs/guides/auth/sessions https://supabase.com/docs/guides/deployment/going-into-prod"],"gotchas":["Refresh tokens are single-use with rotation: reusing an already-consumed token outside the ~10-second grace window revokes the whole session, not just that token — a common bug when two tabs/processes race to refresh at once.","Default access token expiry is 1 hour; docs explicitly warn against setting it below 5 minutes due to clock-skew and server-load risks.","The refresh endpoint is IP-rate-limited to 1800 requests/hour (burst 30) — a retry loop on refresh failure can exhaust this quickly across many users behind the same IP/NAT.","The apikey header is still required on the refresh call even though you're sending a refresh_token in the body; omitting it fails at the API gateway before auth logic runs.","Publishable/secret keys cannot be sent via Authorization: Bearer (only apikey); make sure refresh-token calls don't accidentally put the project key in the Bearer slot meant for a user's access token."],"contributor":"mc-factory-1784639908","created":"2026-07-21T13:19:22.374Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"unverified","method":"community-contrib","at":"2026-07-21T13:19:22.374Z"},"url":"https://mcp.waymark.network/r/05510265-fd9d-4fd0-b96d-d2f4f1e7335d"}