Auth0 在后续轮询请求令牌后返回状态代码 400

问题描述 投票:0回答:1

我正在尝试在 Go 中的 CLI 上执行设备授权流程。我已按照 https://auth0.com/blog/securing-a-python-cli-application-with-auth0/ 中的步骤在 Auth0 中设置我的应用程序。成功请求设备代码后,我尝试获取请求令牌。

// Gets a request token.
func (loginJob *LoginJob) GetRequestToken(deviceCodeData loginResponse.LResponse) error {
    //Setup an http request to retreive a request token.
    url := loginJob.Domain + "/oauth/token"
    method := "POST"
    payload := strings.NewReader("grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code&device_code=" +
        deviceCodeData.DeviceCode + "&client_id=" + loginJob.ClientID)

    client := &http.Client{}
    req, reqErr := http.NewRequest(method, url, payload)
    if reqErr != nil {
        fmt.Println(reqErr)
        return reqErr
    }
    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    authenticate := false
    for !authenticate {
        authenticate = PollRequestTokenStatus(req, client)
        time.Sleep(time.Duration(deviceCodeData.Interval) * time.Second)
    }
    return nil
}

func PollRequestTokenStatus(req *http.Request, client *http.Client) bool {
    res, resErr := client.Do(req)
    if resErr != nil {
        log.Panic(resErr)
        return true
    }
    defer res.Body.Close()
    body, ReadAllErr := io.ReadAll(res.Body)
    if ReadAllErr != nil {
        fmt.Println(ReadAllErr)
        return true
    }
    fmt.Println("res.Body: ")
    fmt.Println(string(body))
    if res.StatusCode == 200 {
        fmt.Println("Authenticated!")
        fmt.Println("- Id Token: ")
        return true
    } else if res.StatusCode == 400 {
        fmt.Println("res.StatusCode: ")
        fmt.Print(res.StatusCode)
        return false
    } else {
        fmt.Println("res.StatusCode: ")
        fmt.Print(res.StatusCode)
    }
    return false
}

我的想法是,我以特定的时间间隔轮询 Auth0 来获取请求令牌。我第一次投票时,收到 403 Forbidden:

{"error":"authorization_pending","error_description":"User has yet to authorize device code."}

但是,在随后的民意调查中,我收到 400 Bad Request:

<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>cloudflare</center>
</body>
</html>

我不确定为什么会发生这种情况。我尝试过使用 Postman 手动轮询 Auth0,并且我总是设法使用 Postman 避免错误 400。 我该如何解决这个问题?

更新:由于某种原因,Go 每当调用 *http.Client.Do() 时都会重置所有请求标头,所以我尝试将请求构造移到 for 循环内。现在我的代码如下所示:

// Gets a request token.
func (loginJob *LoginJob) GetRequestToken(deviceCodeData loginResponse.LResponse) error {
    // Setup an http request to retreive a request token.
    url := loginJob.Domain + "/oauth/token"
    method := "POST"
    payload := strings.NewReader("grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code&device_code=" +
        deviceCodeData.DeviceCode + "&client_id=" + loginJob.ClientID)
    authenticate := false
    var pollErr error
    for !authenticate {
        authenticate, pollErr = loginJob.PollRequestTokenStatus(url, method, payload, deviceCodeData)
        if pollErr != nil {
            log.Panic(pollErr)
        }
        time.Sleep(time.Duration(deviceCodeData.Interval) * time.Second)
    }
    return nil
}

func (loginJob *LoginJob) PollRequestTokenStatus(url string, method string, payload *strings.Reader, deviceCodeData loginResponse.LResponse) (bool, error) {
// Setup an http request to retreive a request token.
    client := &http.Client{
        Timeout: time.Second * 10,
    }
    req, reqErr := http.NewRequest(method, url, payload)
    if reqErr != nil {
        fmt.Println(reqErr)
        return false, reqErr
    }
    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    res, resErr := client.Do(req)
    if resErr != nil {
        fmt.Println(resErr)
        return false, resErr
    }
    defer res.Body.Close()
    fmt.Println("res.StatusCode:")
    fmt.Println(res.StatusCode)
    if res.StatusCode == 200 {
        fmt.Println("Authenticated!")
        fmt.Println("- Id Token: ")
        return true, nil
    } else if res.StatusCode == 400 {
        return true, nil
    }
    return false, nil
}

我现在有一个不同的问题。我在后续民意调查中没有返回错误 400,而是收到 401:

{"error":"access_denied","error_description":"Unauthorized"}
go httprequest auth0
1个回答
0
投票

结果我需要在 for 循环中实例化 strings.Reader 。我的代码现在如下。

// Gets a request token.
func (loginJob *LoginJob) GetRequestToken() error {
    url := loginJob.Domain + "/oauth/token"
    method := "POST"
    authenticate := false
    var pollErr error
    //Keep polling Auth0 for a request token until status 200 or until invalid grant
    for !authenticate {
        authenticate, pollErr = loginJob.PollRequestTokenStatus(url, method)
        if pollErr != nil {
            log.Panic(pollErr)
        }
        //Sleep for the interval duration in the device code data. If we poll too fast, Auth0 will give 429 status.
        time.Sleep(time.Duration(loginJob.DeviceCodeData.Interval) * time.Second)
    }
    return nil
}

func (loginJob *LoginJob) PollRequestTokenStatus(url string, method string) (bool, error) {
    //Construct a new Reader. This must be done within this function, or else Go will read to the end of the REader and not
    //properly construct our http request.
    payload := strings.NewReader("grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code&device_code=" +
        loginJob.DeviceCodeData.DeviceCode + "&client_id=" + loginJob.ClientID)

    //Create a new http Client. This is done within this function because Go will not erase previous Client settings if we
    //pass a client instance as a parameter, which will mess up our post request.
    client := &http.Client{
        Timeout: time.Second * 10,
    }
    //Construct a new http request. This must be done within this function because Go will nuke the request headers after every
    //call of &http.Client.Do().
    req, reqErr := http.NewRequest(method, url, payload)
    if reqErr != nil {
        fmt.Println(reqErr)
        return false, reqErr
    }
    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    res, resErr := client.Do(req)
    if resErr != nil {
        fmt.Println(resErr)
        return false, resErr
    }
    defer res.Body.Close()
    fmt.Println("res.StatusCode:")
    fmt.Println(res.StatusCode)
    if res.StatusCode == 200 {
        fmt.Println("Authenticated!")
        fmt.Println("- Id Token: ")
        return true, nil
    } else if res.StatusCode == 400 {
        return true, nil
    }
    return false, nil
}
© www.soinside.com 2019 - 2024. All rights reserved.