defer a.mutex.Unlock()
var code ChatGPTDeviceCode
+
err := a.postJSON(ctx, "/api/accounts/deviceauth/usercode", map[string]string{
"client_id": chatgptClientID,
}, &code)
}
var tokens ChatGPTTokenFile
+
err = json.Unmarshal(data, &tokens)
if err == nil && (tokens.AccessToken == "" || tokens.RefreshToken == "" || tokens.AccountID == "") {
err = errors.New("a token or the account ID is missing")
// It keeps the old refresh token and ID token when the answer has none.
func (a *ChatGPTAuth) refresh(ctx context.Context, tokens ChatGPTTokenFile) (ChatGPTTokenFile, error) {
var response ChatGPTTokenResponse
+
err := a.postJSON(ctx, "/oauth/token", map[string]string{
"client_id": chatgptClientID,
"grant_type": "refresh_token",
for {
var grant ChatGPTDeviceGrant
+
status, err := a.post(ctx, "/api/accounts/deviceauth/token", "application/json", body, &grant)
if err == nil && (grant.AuthorizationCode == "" || grant.CodeVerifier == "") {
err = errors.New("device grant has no authorization code or code verifier")
select {
case <-ctx.Done():
timer.Stop()
+
return ChatGPTDeviceGrant{}, fmt.Errorf("wait for approval: %w", ctx.Err())
case <-timer.C:
}
}
var response ChatGPTTokenResponse
+
_, err := a.post(ctx, "/oauth/token", "application/x-www-form-urlencoded", []byte(form.Encode()), &response)
if err != nil {
return ChatGPTTokenFile{}, fmt.Errorf("exchange code for tokens: %w", err)
}
request.Header.Set("Content-Type", contentType)
+
response, err := a.http.Do(request)
if err != nil {
return 0, fmt.Errorf("send request: %w", err)
// none.
func chatgptAccountID(token string) string {
var claims map[string]json.RawMessage
+
if !chatgptDecodeClaims(token, &claims) {
return ""
}