getDeviceToken calls the token endpoint of Auth0 and returns the response.
(ctx context.Context, state State)
| 157 | |
| 158 | // getDeviceToken calls the token endpoint of Auth0 and returns the response. |
| 159 | func (a API) getDeviceToken(ctx context.Context, state State) (TokenResponse, error) { |
| 160 | ctx, cancel := context.WithTimeout(ctx, 1*time.Minute) |
| 161 | defer cancel() |
| 162 | |
| 163 | data := url.Values{ |
| 164 | "client_id": {a.ClientID}, |
| 165 | "grant_type": {"urn:ietf:params:oauth:grant-type:device_code"}, |
| 166 | "device_code": {state.DeviceCode}, |
| 167 | } |
| 168 | oauthTokenURL := a.TenantURL + "/oauth/token" |
| 169 | |
| 170 | resp, err := postForm(ctx, oauthTokenURL, strings.NewReader(data.Encode())) |
| 171 | if err != nil { |
| 172 | return TokenResponse{}, fmt.Errorf("failed to get tokens: %w", err) |
| 173 | } |
| 174 | defer func() { |
| 175 | _ = resp.Body.Close() |
| 176 | }() |
| 177 | |
| 178 | // this endpoint returns a 403 with an `authorization_pending` error until the |
| 179 | // user has authenticated, so we don't check the status code here and instead |
| 180 | // decode the response and check for the error. |
| 181 | var res TokenResponse |
| 182 | err = json.NewDecoder(resp.Body).Decode(&res) |
| 183 | if err != nil { |
| 184 | return res, fmt.Errorf("failed to decode response: %w", err) |
| 185 | } |
| 186 | |
| 187 | return res, nil |
| 188 | } |
| 189 | |
| 190 | // RevokeToken revokes a refresh token with the tenant so that it can no longer |
| 191 | // be used to get new tokens. |