| 296 | } |
| 297 | |
| 298 | func isInsufficientScopeError(r *http.Response) error { |
| 299 | if r.StatusCode != 403 { |
| 300 | return nil |
| 301 | } |
| 302 | |
| 303 | type ErrorBody struct { |
| 304 | ErrorCode string `json:"errorCode"` |
| 305 | Message string `json:"message"` |
| 306 | } |
| 307 | |
| 308 | var body ErrorBody |
| 309 | if err := json.NewDecoder(r.Body).Decode(&body); err != nil { |
| 310 | return nil |
| 311 | } |
| 312 | |
| 313 | if body.ErrorCode != "insufficient_scope" { |
| 314 | return nil |
| 315 | } |
| 316 | |
| 317 | var recommendedScopeToAdd string |
| 318 | |
| 319 | parts := strings.Split(body.Message, "Insufficient scope, expected any of: ") |
| 320 | if len(parts) > 1 { |
| 321 | missingScopes := parts[1] |
| 322 | recommendedScopeToAdd = strings.Split(missingScopes, ",")[0] |
| 323 | } else { |
| 324 | re := regexp.MustCompile(`scope: ([\w:,_\s]+)`) |
| 325 | matches := re.FindStringSubmatch(body.Message) |
| 326 | if len(matches) > 1 { |
| 327 | recommendedScopeToAdd = matches[1] |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | return fmt.Errorf( |
| 332 | "request failed because access token lacks scope: %s.\n "+ |
| 333 | "If authenticated via client credentials, add this scope to the designated client. "+ |
| 334 | "If authenticated as a user, request this scope during login by running `auth0 login --scopes %s`", |
| 335 | recommendedScopeToAdd, |
| 336 | recommendedScopeToAdd, |
| 337 | ) |
| 338 | } |