Withings OAuth
Mushu handles the Withings OAuth flow so your app can sync body composition data (weight, BMI, body fat, muscle mass) from Withings devices. Users authorize once; Mushu stores the tokens and handles refresh automatically.
How It Works
- Your app opens the Withings authorization URL (with your
redirect_uri) - User grants access in the Withings UI
- Withings redirects to Mushu's callback, which exchanges the code for tokens
- Mushu redirects to your
redirect_uri— your app resumes - Your app calls
POST /withings/sync/{user_id}to pull measurements
Setup: Register Redirect URIs
Before initiating OAuth, register your app's allowed redirect URIs. Mushu validates
the redirect_uri param against this allowlist — unregistered URIs are rejected.
Register via CLI:
mushu health redirect-uri add womoji://withings/success --app YOUR_APP_ID
mushu health redirect-uri list --app YOUR_APP_ID Or via the dashboard: open your app → Health tab → Redirect URIs.
You can register multiple URIs (e.g. a custom scheme for iOS, an HTTPS URL for web). Any registered URI can be used at auth time.
Initiate OAuth
GET https://health.mushucorp.com/apps/{app_id}/withings/auth
?user_id=YOUR_USER_ID
&redirect_uri=womoji://withings/success | Parameter | Required | Description |
|---|---|---|
user_id | Yes | Your app's user identifier |
redirect_uri | Yes | Where to send the user after OAuth completes. Must be pre-registered. |
This endpoint returns a redirect to Withings. Open it in a browser or ASWebAuthenticationSession.
iOS: ASWebAuthenticationSession
Use ASWebAuthenticationSession with your custom scheme as callbackURLScheme.
The session auto-dismisses when Mushu redirects to your URI after the OAuth callback.
import AuthenticationServices
func connectWithings(userId: String) {
let authURL = URL(string: """
https://health.mushucorp.com/apps/\(appId)/withings/auth
?user_id=\(userId)
&redirect_uri=womoji://withings/success
""".components(separatedBy: .whitespacesAndNewlines).joined())!
let session = ASWebAuthenticationSession(
url: authURL,
callbackURLScheme: "womoji" // must match your redirect_uri scheme
) { callbackURL, error in
guard error == nil else { return }
// OAuth complete — sync measurements
syncWithings(userId: userId)
}
session.presentationContextProvider = self
session.start()
} Important: callbackURLScheme must match the scheme in your
redirect_uri. If they don't match, ASWebAuthenticationSession
will not intercept the callback and the sheet won't dismiss automatically.
Sync Measurements
After OAuth completes, pull the user's latest measurements:
POST https://health.mushucorp.com/apps/{app_id}/withings/sync/{user_id}
X-API-Key: YOUR_API_KEY Mushu fetches from Withings and stores the data. Metrics are available immediately via the metrics API.
Check Connection Status
GET https://health.mushucorp.com/apps/{app_id}/withings/status/{user_id}
X-API-Key: YOUR_API_KEY Returns { "connected": true } or { "connected": false }.
Disconnect
DELETE https://health.mushucorp.com/apps/{app_id}/withings/disconnect/{user_id}
X-API-Key: YOUR_API_KEY Revokes Mushu's stored Withings tokens for this user. Does not revoke access on the Withings side.
Troubleshooting
ASWebAuthenticationSession sheet doesn't dismiss
The session only auto-dismisses when the callback URL matches callbackURLScheme.
Make sure:
- Your
redirect_uriuses a custom scheme (e.g.womoji://, nothttps://) callbackURLSchemematches that scheme exactly- The URI is registered in your app's Mushu health config
"redirect_uri not allowed" error
The URI wasn't registered. Run mushu health redirect-uri add YOUR_URI --app YOUR_APP_ID
and try again.