Fix immediate log out #1

Closed
opened 2026-05-28 11:11:52 +02:00 by hloth · 5 comments
Owner

Observed on Firefox Android

Observed on Firefox Android
Author
Owner

Grindr Web auth flow for desktop and Android:

  1. Both issue POST https://web.grindr.com/v1/api-tokens/, both get GRINDR_WEB_SESSION cookie in response
  2. Both make same requests, get one failed with 401 (see issue #2), same for both versions
  3. Desktop connects to WebSocket GET wss://grindr.mobi/v1/ws, Android skips it and loads much later (after step 6)
  4. Both load some static assets
  5. Desktop sends PUT https://web.grindr.com/api/v3/me/location, Android skips it for some reason
  6. Desktop sends GET https://web.grindr.com/api/v3/cascade/?nearbyGeoHash=<geohash>&pageNumber=1, Android does not send it because it has no geohash
  7. Both send empty POST https://web.grindr.com/v1/api-tokens/ again, but Android's results in 400 Bad Request response
  8. Since 400 bad requests aren't handled, Android sends DELETE https://web.grindr.com/v1/api-tokens/ and logs out locally

Desktop:

  • User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0
  • DNT: 1
  • Cookies:
    • __cf_bm
    • _ketch_consent_v1_
    • _swb
    • GRINDR_WEB_SESSION

Mobile:

  • User-Agent: Mozilla/5.0 (Android 16; Mobile; rv:151.0) Gecko/151.0 Firefox/151.0
  • No DNT: 1
  • Cookies:
    • __cf_bm
    • _ketch_consent_v1_
    • _swb
    • _swb_consent_ ⚠️
    • GRINDR_WEB_SESSION
    • usprivacy ⚠️
    • us_privacy ⚠️
Grindr Web auth flow for desktop and Android: 1. Both issue `POST https://web.grindr.com/v1/api-tokens/`, both get `GRINDR_WEB_SESSION` cookie in response 2. Both make same requests, get one failed with 401 (see issue #2), same for both versions 3. Desktop connects to WebSocket `GET wss://grindr.mobi/v1/ws`, Android skips it and loads much later (after step 6) 4. Both load some static assets 5. Desktop sends `PUT https://web.grindr.com/api/v3/me/location`, Android skips it for some reason 6. Desktop sends `GET https://web.grindr.com/api/v3/cascade/?nearbyGeoHash=<geohash>&pageNumber=1`, Android does not send it because it has no geohash 7. Both send empty `POST https://web.grindr.com/v1/api-tokens/` again, but Android's results in 400 Bad Request response 8. Since 400 bad requests aren't handled, Android sends `DELETE https://web.grindr.com/v1/api-tokens/` and logs out locally Desktop: - `User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:150.0) Gecko/20100101 Firefox/150.0` - `DNT: 1` - Cookies: - `__cf_bm` ✅ - `_ketch_consent_v1_` ✅ - `_swb` ✅ - `GRINDR_WEB_SESSION` ✅ Mobile: - `User-Agent: Mozilla/5.0 (Android 16; Mobile; rv:151.0) Gecko/151.0 Firefox/151.0` - No `DNT: 1` - Cookies: - `__cf_bm` ✅ - `_ketch_consent_v1_` ✅ - `_swb` ✅ - `_swb_consent_` ⚠️ - `GRINDR_WEB_SESSION` ✅ - `usprivacy` ⚠️ - `us_privacy` ⚠️
Author
Owner

Update: I permanently allowed web.grindr.com to access my location and the mobile flow changed:
3. Android connects to WS (though the connection is aborted due to redirect)
5. Android sends correctly formatted location
6. Android still does not query cascade
Everything else is the same

Update: I permanently allowed web.grindr.com to access my location and the mobile flow changed: 3. Android connects to WS (though the connection is aborted due to redirect) 5. Android sends correctly formatted location 6. Android still does not query cascade Everything else is the same
Author
Owner

Confirmed: the issue is _swb_consent_ cookie presence. If it's passed to https://web.grindr.com/v1/api-tokens/, the backend returns 400 Bad Request and client logs out.

Confirmed: the issue is `_swb_consent_` cookie presence. If it's passed to `https://web.grindr.com/v1/api-tokens/`, the backend returns 400 Bad Request and client logs out.
Author
Owner

Interestingly, the cookie value is a base64-encoded object about GDPR complience. Here is an example observed:

{"collectedAt":1779965486,"controllerCode":"","environmentCode":"production","hasUnrecordedOptInConsent":false,"identities":{"swb_grindr_web":"1bed2a62-8558-41df-ae78-6edbb6658fcb"},"interactive":true,"jurisdictionCode":"eu___gdpr___eprivacy","propertyCode":"grindr_web","purposes":{"actively_scan_device_characteristics_for_identification":{"allowed":"false","legalBasisCode":"consent_optin"},"analytics":{"allowed":"false","legalBasisCode":"consent_optin"},"behavioral_advertising":{"allowed":"false","legalBasisCode":"consent_optin"},"create_profiles_for_personalised_advertising":{"allowed":"false","legalBasisCode":"consent_optin"},"create_profiles_to_personalise_content":{"allowed":"false","legalBasisCode":"consent_optin"},"develop_and_improve_services":{"allowed":"true","legalBasisCode":"legitimateinterest"},"essential_services":{"allowed":"true","legalBasisCode":"legitimateinterest"},"functional":{"allowed":"false","legalBasisCode":"consent_optin"},"measure_advertising_performance":{"allowed":"true","legalBasisCode":"legitimateinterest"},"measure_content_performance":{"allowed":"false","legalBasisCode":"legitimateinterest_objectable"},"store_and_or_access_information_on_a_device":{"allowed":"false","legalBasisCode":"consent_optin"},"understand_audiences_through_statistics_or_combinations_of_data":{"allowed":"true","legalBasisCode":"legitimateinterest"},"use_limited_data_to_select_advertising":{"allowed":"true","legalBasisCode":"legitimateinterest"},"use_limited_data_to_select_content":{"allowed":"true","legalBasisCode":"legitimateinterest"},"use_precise_geolocation_data":{"allowed":"false","legalBasisCode":"consent_optin"},"use_profiles_to_select_personalised_advertising":{"allowed":"false","legalBasisCode":"consent_optin"},"use_profiles_to_select_personalised_content":{"allowed":"false","legalBasisCode":"consent_optin"}},"setConsentRequired":false,"cachedAt":1779970195}
Interestingly, the cookie value is a base64-encoded object about GDPR complience. Here is an example observed: ```json {"collectedAt":1779965486,"controllerCode":"","environmentCode":"production","hasUnrecordedOptInConsent":false,"identities":{"swb_grindr_web":"1bed2a62-8558-41df-ae78-6edbb6658fcb"},"interactive":true,"jurisdictionCode":"eu___gdpr___eprivacy","propertyCode":"grindr_web","purposes":{"actively_scan_device_characteristics_for_identification":{"allowed":"false","legalBasisCode":"consent_optin"},"analytics":{"allowed":"false","legalBasisCode":"consent_optin"},"behavioral_advertising":{"allowed":"false","legalBasisCode":"consent_optin"},"create_profiles_for_personalised_advertising":{"allowed":"false","legalBasisCode":"consent_optin"},"create_profiles_to_personalise_content":{"allowed":"false","legalBasisCode":"consent_optin"},"develop_and_improve_services":{"allowed":"true","legalBasisCode":"legitimateinterest"},"essential_services":{"allowed":"true","legalBasisCode":"legitimateinterest"},"functional":{"allowed":"false","legalBasisCode":"consent_optin"},"measure_advertising_performance":{"allowed":"true","legalBasisCode":"legitimateinterest"},"measure_content_performance":{"allowed":"false","legalBasisCode":"legitimateinterest_objectable"},"store_and_or_access_information_on_a_device":{"allowed":"false","legalBasisCode":"consent_optin"},"understand_audiences_through_statistics_or_combinations_of_data":{"allowed":"true","legalBasisCode":"legitimateinterest"},"use_limited_data_to_select_advertising":{"allowed":"true","legalBasisCode":"legitimateinterest"},"use_limited_data_to_select_content":{"allowed":"true","legalBasisCode":"legitimateinterest"},"use_precise_geolocation_data":{"allowed":"false","legalBasisCode":"consent_optin"},"use_profiles_to_select_personalised_advertising":{"allowed":"false","legalBasisCode":"consent_optin"},"use_profiles_to_select_personalised_content":{"allowed":"false","legalBasisCode":"consent_optin"}},"setConsentRequired":false,"cachedAt":1779970195} ```
Author
Owner

Fixed in 1548fb7a42

Fixed in 1548fb7a42917a2fb10798635387652a935beb3c
hloth closed this issue 2026-05-28 17:46:41 +02:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
open-grind/grindr-web-unlock#1
No description provided.