diff --git a/internal/auth/auth.go b/internal/auth/auth.go index 4ae05b4..384112c 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -178,7 +178,7 @@ func exchangeCode(code, redirectURI, clientID, clientSecret string) error { AccessToken: resp.AccessToken, RefreshToken: resp.RefreshToken, ExpiresAt: time.Now().Add(time.Duration(resp.ExpiresIn) * time.Second).Add(-5 * time.Minute), - UserID: resp.UserID, + UserID: resp.UserID.String(), ClientID: clientID, ClientSecret: clientSecret, } @@ -201,19 +201,19 @@ func refresh(store *TokenStore) error { store.AccessToken = resp.AccessToken store.RefreshToken = resp.RefreshToken store.ExpiresAt = time.Now().Add(time.Duration(resp.ExpiresIn) * time.Second).Add(-5 * time.Minute) - if resp.UserID != "" { - store.UserID = resp.UserID + if resp.UserID.String() != "" { + store.UserID = resp.UserID.String() } return save(store) } type tokenResponse struct { - UserID string `json:"userid"` - AccessToken string `json:"access_token"` - RefreshToken string `json:"refresh_token"` - ExpiresIn int `json:"expires_in"` - Scope string `json:"scope"` - TokenType string `json:"token_type"` + UserID json.Number `json:"userid"` + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` + ExpiresIn int `json:"expires_in"` + Scope string `json:"scope"` + TokenType string `json:"token_type"` } func postToken(form url.Values, out *tokenResponse) error { diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go new file mode 100644 index 0000000..d77a704 --- /dev/null +++ b/internal/auth/auth_test.go @@ -0,0 +1,30 @@ +package auth + +import ( + "encoding/json" + "testing" +) + +// Withings returns userid as a JSON string on the initial authorization_code +// grant and as a JSON number on the refresh_token grant. tokenResponse.UserID +// must unmarshal both without error — json.Number accepts either form. +func TestTokenResponse_UserIDUnmarshalsStringAndNumber(t *testing.T) { + cases := []struct { + name string + body string + }{ + {"string form (initial login)", `{"userid":"12345","access_token":"a","refresh_token":"r","expires_in":10800,"scope":"s","token_type":"Bearer"}`}, + {"number form (refresh)", `{"userid":12345,"access_token":"a","refresh_token":"r","expires_in":10800,"scope":"s","token_type":"Bearer"}`}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + var resp tokenResponse + if err := json.Unmarshal([]byte(tc.body), &resp); err != nil { + t.Fatalf("unmarshal failed: %v", err) + } + if resp.UserID.String() != "12345" { + t.Fatalf("UserID = %q, want %q", resp.UserID.String(), "12345") + } + }) + } +}