|
Packit |
63bb0d |
package autorest
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Copyright 2017 Microsoft Corporation
|
|
Packit |
63bb0d |
//
|
|
Packit |
63bb0d |
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
Packit |
63bb0d |
// you may not use this file except in compliance with the License.
|
|
Packit |
63bb0d |
// You may obtain a copy of the License at
|
|
Packit |
63bb0d |
//
|
|
Packit |
63bb0d |
// http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
63bb0d |
//
|
|
Packit |
63bb0d |
// Unless required by applicable law or agreed to in writing, software
|
|
Packit |
63bb0d |
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
63bb0d |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
63bb0d |
// See the License for the specific language governing permissions and
|
|
Packit |
63bb0d |
// limitations under the License.
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
import (
|
|
Packit |
63bb0d |
"crypto/tls"
|
|
Packit |
63bb0d |
"encoding/base64"
|
|
Packit |
63bb0d |
"fmt"
|
|
Packit |
63bb0d |
"net/http"
|
|
Packit |
63bb0d |
"net/url"
|
|
Packit |
63bb0d |
"strings"
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
"github.com/Azure/go-autorest/autorest/adal"
|
|
Packit |
63bb0d |
)
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
const (
|
|
Packit |
63bb0d |
bearerChallengeHeader = "Www-Authenticate"
|
|
Packit |
63bb0d |
bearer = "Bearer"
|
|
Packit |
63bb0d |
tenantID = "tenantID"
|
|
Packit |
63bb0d |
apiKeyAuthorizerHeader = "Ocp-Apim-Subscription-Key"
|
|
Packit |
63bb0d |
bingAPISdkHeader = "X-BingApis-SDK-Client"
|
|
Packit |
63bb0d |
golangBingAPISdkHeaderValue = "Go-SDK"
|
|
Packit |
63bb0d |
authorization = "Authorization"
|
|
Packit |
63bb0d |
basic = "Basic"
|
|
Packit |
63bb0d |
)
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Authorizer is the interface that provides a PrepareDecorator used to supply request
|
|
Packit |
63bb0d |
// authorization. Most often, the Authorizer decorator runs last so it has access to the full
|
|
Packit |
63bb0d |
// state of the formed HTTP request.
|
|
Packit |
63bb0d |
type Authorizer interface {
|
|
Packit |
63bb0d |
WithAuthorization() PrepareDecorator
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// NullAuthorizer implements a default, "do nothing" Authorizer.
|
|
Packit |
63bb0d |
type NullAuthorizer struct{}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// WithAuthorization returns a PrepareDecorator that does nothing.
|
|
Packit |
63bb0d |
func (na NullAuthorizer) WithAuthorization() PrepareDecorator {
|
|
Packit |
63bb0d |
return WithNothing()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// APIKeyAuthorizer implements API Key authorization.
|
|
Packit |
63bb0d |
type APIKeyAuthorizer struct {
|
|
Packit |
63bb0d |
headers map[string]interface{}
|
|
Packit |
63bb0d |
queryParameters map[string]interface{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// NewAPIKeyAuthorizerWithHeaders creates an ApiKeyAuthorizer with headers.
|
|
Packit |
63bb0d |
func NewAPIKeyAuthorizerWithHeaders(headers map[string]interface{}) *APIKeyAuthorizer {
|
|
Packit |
63bb0d |
return NewAPIKeyAuthorizer(headers, nil)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// NewAPIKeyAuthorizerWithQueryParameters creates an ApiKeyAuthorizer with query parameters.
|
|
Packit |
63bb0d |
func NewAPIKeyAuthorizerWithQueryParameters(queryParameters map[string]interface{}) *APIKeyAuthorizer {
|
|
Packit |
63bb0d |
return NewAPIKeyAuthorizer(nil, queryParameters)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// NewAPIKeyAuthorizer creates an ApiKeyAuthorizer with headers.
|
|
Packit |
63bb0d |
func NewAPIKeyAuthorizer(headers map[string]interface{}, queryParameters map[string]interface{}) *APIKeyAuthorizer {
|
|
Packit |
63bb0d |
return &APIKeyAuthorizer{headers: headers, queryParameters: queryParameters}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// WithAuthorization returns a PrepareDecorator that adds an HTTP headers and Query Parameters.
|
|
Packit |
63bb0d |
func (aka *APIKeyAuthorizer) WithAuthorization() PrepareDecorator {
|
|
Packit |
63bb0d |
return func(p Preparer) Preparer {
|
|
Packit |
63bb0d |
return DecoratePreparer(p, WithHeaders(aka.headers), WithQueryParameters(aka.queryParameters))
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// CognitiveServicesAuthorizer implements authorization for Cognitive Services.
|
|
Packit |
63bb0d |
type CognitiveServicesAuthorizer struct {
|
|
Packit |
63bb0d |
subscriptionKey string
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// NewCognitiveServicesAuthorizer is
|
|
Packit |
63bb0d |
func NewCognitiveServicesAuthorizer(subscriptionKey string) *CognitiveServicesAuthorizer {
|
|
Packit |
63bb0d |
return &CognitiveServicesAuthorizer{subscriptionKey: subscriptionKey}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// WithAuthorization is
|
|
Packit |
63bb0d |
func (csa *CognitiveServicesAuthorizer) WithAuthorization() PrepareDecorator {
|
|
Packit |
63bb0d |
headers := make(map[string]interface{})
|
|
Packit |
63bb0d |
headers[apiKeyAuthorizerHeader] = csa.subscriptionKey
|
|
Packit |
63bb0d |
headers[bingAPISdkHeader] = golangBingAPISdkHeaderValue
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
return NewAPIKeyAuthorizerWithHeaders(headers).WithAuthorization()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// BearerAuthorizer implements the bearer authorization
|
|
Packit |
63bb0d |
type BearerAuthorizer struct {
|
|
Packit |
63bb0d |
tokenProvider adal.OAuthTokenProvider
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// NewBearerAuthorizer crates a BearerAuthorizer using the given token provider
|
|
Packit |
63bb0d |
func NewBearerAuthorizer(tp adal.OAuthTokenProvider) *BearerAuthorizer {
|
|
Packit |
63bb0d |
return &BearerAuthorizer{tokenProvider: tp}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
|
|
Packit |
63bb0d |
// value is "Bearer " followed by the token.
|
|
Packit |
63bb0d |
//
|
|
Packit |
63bb0d |
// By default, the token will be automatically refreshed through the Refresher interface.
|
|
Packit |
63bb0d |
func (ba *BearerAuthorizer) WithAuthorization() PrepareDecorator {
|
|
Packit |
63bb0d |
return func(p Preparer) Preparer {
|
|
Packit |
63bb0d |
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
|
Packit |
63bb0d |
r, err := p.Prepare(r)
|
|
Packit |
63bb0d |
if err == nil {
|
|
Packit |
63bb0d |
// the ordering is important here, prefer RefresherWithContext if available
|
|
Packit |
63bb0d |
if refresher, ok := ba.tokenProvider.(adal.RefresherWithContext); ok {
|
|
Packit |
63bb0d |
err = refresher.EnsureFreshWithContext(r.Context())
|
|
Packit |
63bb0d |
} else if refresher, ok := ba.tokenProvider.(adal.Refresher); ok {
|
|
Packit |
63bb0d |
err = refresher.EnsureFresh()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if err != nil {
|
|
Packit |
63bb0d |
var resp *http.Response
|
|
Packit |
63bb0d |
if tokError, ok := err.(adal.TokenRefreshError); ok {
|
|
Packit |
63bb0d |
resp = tokError.Response()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return r, NewErrorWithError(err, "azure.BearerAuthorizer", "WithAuthorization", resp,
|
|
Packit |
63bb0d |
"Failed to refresh the Token for request to %s", r.URL)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return Prepare(r, WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", ba.tokenProvider.OAuthToken())))
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return r, err
|
|
Packit |
63bb0d |
})
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// BearerAuthorizerCallbackFunc is the authentication callback signature.
|
|
Packit |
63bb0d |
type BearerAuthorizerCallbackFunc func(tenantID, resource string) (*BearerAuthorizer, error)
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// BearerAuthorizerCallback implements bearer authorization via a callback.
|
|
Packit |
63bb0d |
type BearerAuthorizerCallback struct {
|
|
Packit |
63bb0d |
sender Sender
|
|
Packit |
63bb0d |
callback BearerAuthorizerCallbackFunc
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// NewBearerAuthorizerCallback creates a bearer authorization callback. The callback
|
|
Packit |
63bb0d |
// is invoked when the HTTP request is submitted.
|
|
Packit |
63bb0d |
func NewBearerAuthorizerCallback(s Sender, callback BearerAuthorizerCallbackFunc) *BearerAuthorizerCallback {
|
|
Packit |
63bb0d |
if s == nil {
|
|
Packit |
63bb0d |
s = sender(tls.RenegotiateNever)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return &BearerAuthorizerCallback{sender: s, callback: callback}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose value
|
|
Packit |
63bb0d |
// is "Bearer " followed by the token. The BearerAuthorizer is obtained via a user-supplied callback.
|
|
Packit |
63bb0d |
//
|
|
Packit |
63bb0d |
// By default, the token will be automatically refreshed through the Refresher interface.
|
|
Packit |
63bb0d |
func (bacb *BearerAuthorizerCallback) WithAuthorization() PrepareDecorator {
|
|
Packit |
63bb0d |
return func(p Preparer) Preparer {
|
|
Packit |
63bb0d |
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
|
Packit |
63bb0d |
r, err := p.Prepare(r)
|
|
Packit |
63bb0d |
if err == nil {
|
|
Packit |
63bb0d |
// make a copy of the request and remove the body as it's not
|
|
Packit |
63bb0d |
// required and avoids us having to create a copy of it.
|
|
Packit |
63bb0d |
rCopy := *r
|
|
Packit |
63bb0d |
removeRequestBody(&rCopy)
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
resp, err := bacb.sender.Do(&rCopy)
|
|
Packit |
63bb0d |
if err != nil {
|
|
Packit |
63bb0d |
return r, err
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
DrainResponseBody(resp)
|
|
Packit |
63bb0d |
if resp.StatusCode == 401 && hasBearerChallenge(resp.Header) {
|
|
Packit |
63bb0d |
bc, err := newBearerChallenge(resp.Header)
|
|
Packit |
63bb0d |
if err != nil {
|
|
Packit |
63bb0d |
return r, err
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if bacb.callback != nil {
|
|
Packit |
63bb0d |
ba, err := bacb.callback(bc.values[tenantID], bc.values["resource"])
|
|
Packit |
63bb0d |
if err != nil {
|
|
Packit |
63bb0d |
return r, err
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return Prepare(r, ba.WithAuthorization())
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return r, err
|
|
Packit |
63bb0d |
})
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// returns true if the HTTP response contains a bearer challenge
|
|
Packit |
63bb0d |
func hasBearerChallenge(header http.Header) bool {
|
|
Packit |
63bb0d |
authHeader := header.Get(bearerChallengeHeader)
|
|
Packit |
63bb0d |
if len(authHeader) == 0 || strings.Index(authHeader, bearer) < 0 {
|
|
Packit |
63bb0d |
return false
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return true
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
type bearerChallenge struct {
|
|
Packit |
63bb0d |
values map[string]string
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func newBearerChallenge(header http.Header) (bc bearerChallenge, err error) {
|
|
Packit |
63bb0d |
challenge := strings.TrimSpace(header.Get(bearerChallengeHeader))
|
|
Packit |
63bb0d |
trimmedChallenge := challenge[len(bearer)+1:]
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// challenge is a set of key=value pairs that are comma delimited
|
|
Packit |
63bb0d |
pairs := strings.Split(trimmedChallenge, ",")
|
|
Packit |
63bb0d |
if len(pairs) < 1 {
|
|
Packit |
63bb0d |
err = fmt.Errorf("challenge '%s' contains no pairs", challenge)
|
|
Packit |
63bb0d |
return bc, err
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
bc.values = make(map[string]string)
|
|
Packit |
63bb0d |
for i := range pairs {
|
|
Packit |
63bb0d |
trimmedPair := strings.TrimSpace(pairs[i])
|
|
Packit |
63bb0d |
pair := strings.Split(trimmedPair, "=")
|
|
Packit |
63bb0d |
if len(pair) == 2 {
|
|
Packit |
63bb0d |
// remove the enclosing quotes
|
|
Packit |
63bb0d |
key := strings.Trim(pair[0], "\"")
|
|
Packit |
63bb0d |
value := strings.Trim(pair[1], "\"")
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
switch key {
|
|
Packit |
63bb0d |
case "authorization", "authorization_uri":
|
|
Packit |
63bb0d |
// strip the tenant ID from the authorization URL
|
|
Packit |
63bb0d |
asURL, err := url.Parse(value)
|
|
Packit |
63bb0d |
if err != nil {
|
|
Packit |
63bb0d |
return bc, err
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
bc.values[tenantID] = asURL.Path[1:]
|
|
Packit |
63bb0d |
default:
|
|
Packit |
63bb0d |
bc.values[key] = value
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
return bc, err
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// EventGridKeyAuthorizer implements authorization for event grid using key authentication.
|
|
Packit |
63bb0d |
type EventGridKeyAuthorizer struct {
|
|
Packit |
63bb0d |
topicKey string
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// NewEventGridKeyAuthorizer creates a new EventGridKeyAuthorizer
|
|
Packit |
63bb0d |
// with the specified topic key.
|
|
Packit |
63bb0d |
func NewEventGridKeyAuthorizer(topicKey string) EventGridKeyAuthorizer {
|
|
Packit |
63bb0d |
return EventGridKeyAuthorizer{topicKey: topicKey}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// WithAuthorization returns a PrepareDecorator that adds the aeg-sas-key authentication header.
|
|
Packit |
63bb0d |
func (egta EventGridKeyAuthorizer) WithAuthorization() PrepareDecorator {
|
|
Packit |
63bb0d |
headers := map[string]interface{}{
|
|
Packit |
63bb0d |
"aeg-sas-key": egta.topicKey,
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return NewAPIKeyAuthorizerWithHeaders(headers).WithAuthorization()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// BasicAuthorizer implements basic HTTP authorization by adding the Authorization HTTP header
|
|
Packit |
63bb0d |
// with the value "Basic <TOKEN>" where <TOKEN> is a base64-encoded username:password tuple.
|
|
Packit |
63bb0d |
type BasicAuthorizer struct {
|
|
Packit |
63bb0d |
userName string
|
|
Packit |
63bb0d |
password string
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// NewBasicAuthorizer creates a new BasicAuthorizer with the specified username and password.
|
|
Packit |
63bb0d |
func NewBasicAuthorizer(userName, password string) *BasicAuthorizer {
|
|
Packit |
63bb0d |
return &BasicAuthorizer{
|
|
Packit |
63bb0d |
userName: userName,
|
|
Packit |
63bb0d |
password: password,
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
|
|
Packit |
63bb0d |
// value is "Basic " followed by the base64-encoded username:password tuple.
|
|
Packit |
63bb0d |
func (ba *BasicAuthorizer) WithAuthorization() PrepareDecorator {
|
|
Packit |
63bb0d |
headers := make(map[string]interface{})
|
|
Packit |
63bb0d |
headers[authorization] = basic + " " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", ba.userName, ba.password)))
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
return NewAPIKeyAuthorizerWithHeaders(headers).WithAuthorization()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// MultiTenantServicePrincipalTokenAuthorizer provides authentication across tenants.
|
|
Packit |
63bb0d |
type MultiTenantServicePrincipalTokenAuthorizer interface {
|
|
Packit |
63bb0d |
WithAuthorization() PrepareDecorator
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// NewMultiTenantServicePrincipalTokenAuthorizer crates a BearerAuthorizer using the given token provider
|
|
Packit |
63bb0d |
func NewMultiTenantServicePrincipalTokenAuthorizer(tp adal.MultitenantOAuthTokenProvider) MultiTenantServicePrincipalTokenAuthorizer {
|
|
Packit |
63bb0d |
return &multiTenantSPTAuthorizer{tp: tp}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
type multiTenantSPTAuthorizer struct {
|
|
Packit |
63bb0d |
tp adal.MultitenantOAuthTokenProvider
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header using the
|
|
Packit |
63bb0d |
// primary token along with the auxiliary authorization header using the auxiliary tokens.
|
|
Packit |
63bb0d |
//
|
|
Packit |
63bb0d |
// By default, the token will be automatically refreshed through the Refresher interface.
|
|
Packit |
63bb0d |
func (mt multiTenantSPTAuthorizer) WithAuthorization() PrepareDecorator {
|
|
Packit |
63bb0d |
return func(p Preparer) Preparer {
|
|
Packit |
63bb0d |
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
|
Packit |
63bb0d |
r, err := p.Prepare(r)
|
|
Packit |
63bb0d |
if err != nil {
|
|
Packit |
63bb0d |
return r, err
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if refresher, ok := mt.tp.(adal.RefresherWithContext); ok {
|
|
Packit |
63bb0d |
err = refresher.EnsureFreshWithContext(r.Context())
|
|
Packit |
63bb0d |
if err != nil {
|
|
Packit |
63bb0d |
var resp *http.Response
|
|
Packit |
63bb0d |
if tokError, ok := err.(adal.TokenRefreshError); ok {
|
|
Packit |
63bb0d |
resp = tokError.Response()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return r, NewErrorWithError(err, "azure.multiTenantSPTAuthorizer", "WithAuthorization", resp,
|
|
Packit |
63bb0d |
"Failed to refresh one or more Tokens for request to %s", r.URL)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
r, err = Prepare(r, WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", mt.tp.PrimaryOAuthToken())))
|
|
Packit |
63bb0d |
if err != nil {
|
|
Packit |
63bb0d |
return r, err
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
auxTokens := mt.tp.AuxiliaryOAuthTokens()
|
|
Packit |
63bb0d |
for i := range auxTokens {
|
|
Packit |
63bb0d |
auxTokens[i] = fmt.Sprintf("Bearer %s", auxTokens[i])
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return Prepare(r, WithHeader(headerAuxAuthorization, strings.Join(auxTokens, "; ")))
|
|
Packit |
63bb0d |
})
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|