如何添加自定义身份验证承载令牌以执行oauth2 Exchange功能?

时间:2017-09-20 11:58:15

标签: go oauth-2.0

我们有一个oauth2端点,似乎需要一个client_credentials令牌作为承载用于令牌交换过程的初始代码。我已经成功获得了令牌。

但是,在go的oauth2客户端lib的当前实现中,Exchange()函数(参见:Exchange最终调用RetrieveToken

它没有添加“身份验证:承载”标头,其中包含我可以在Exchange期间插入的令牌。但是,它可以添加Basic auth标头。我们的实现目前不支持基本身份验证。

如果可能的话,我想让它添加标题而不修改源代码到oauth2包。

如果我调用oauth2.RegisterBrokenAuthHeaderProvider,它可能会跳过尝试添加我的情况下需要的基本身份验证头,因为它不起作用。

然后最后调用http请求设置为POST。

代码:

func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values) (*Token, error) {
    hc, err := ContextClient(ctx)
    if err != nil {
        return nil, err
    }
    bustedAuth := !providerAuthHeaderWorks(tokenURL)
    if bustedAuth {
        if clientID != "" {
            v.Set("client_id", clientID)
        }
        if clientSecret != "" {
            v.Set("client_secret", clientSecret)
        }
    }
    req, err := http.NewRequest("POST", tokenURL, strings.NewReader(v.Encode()))
    if err != nil {
        return nil, err
    }
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    if !bustedAuth {
        req.SetBasicAuth(url.QueryEscape(clientID), url.QueryEscape(clientSecret))
    }
    r, err := ctxhttp.Do(ctx, hc, req)
    if err != nil {
        return nil, err
    }

  // rest of code ...
}

ctxhttp.Do可以采用上下文。我一直在读这些,但我不明白它们是如何工作的。我可以使用它们来添加我的标题或我可能需要的任何其他标题吗?

1 个答案:

答案 0 :(得分:0)

我不确定这是否是最佳方式,但它似乎有效。这是由于访问auth端点而调用的重定向回调处理程序。

// Create a custom tokenSource type
type tokenSource struct{ token *oauth2.Token }

func (t *tokenSource) Token() (*oauth2.Token, error) {
    fmt.Println("TokenSource!", t.token)
    return t.token, nil
}

func handleCallback(w http.ResponseWriter, r *http.Request) {

    state := r.FormValue("state")
    if state != oauthStateString {
        fmt.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthStateString, state)
        http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
        return
    }

    code := r.FormValue("code")

    // Create a tokenSource and fill in our application Bearer token
    ts := &tokenSource{
        token: &oauth2.Token{
            AccessToken: appToken.AccessToken,
            TokenType: appToken.TokenType,
        },
    }

    tr := &oauth2.Transport{
        Source: ts,
    }

    ctx := context.WithValue(context.Background(), oauth2.HTTPClient, &http.Client{
        Transport: tr,
    })

    // myConfig defined previously and in the usual way. Look at the examples.
    token, err := myConfig.Exchange(ctx, code)
    if err != nil {
        fmt.Printf("Code exchange failed with '%s'\n", err)
        http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
        return
    }

    fmt.Printf("token: %+v", token)

    // token can now be used.
}