1// Copyright 2010 Gary Burd
2//
3// Licensed under the Apache License, Version 2.0 (the "License"): you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations
13// under the License.
14
15// Package oauth is consumer interface for OAuth 1.0, OAuth 1.0a and RFC 5849.
16//
17// Redirection-based Authorization
18//
19// This section outlines how to use the oauth package in redirection-based
20// authorization (http://tools.ietf.org/html/rfc5849#section-2).
21//
22// Step 1: Create a Client using credentials and URIs provided by the server.
23// The Client can be initialized once at application startup and stored in a
24// package-level variable.
25//
26// Step 2: Request temporary credentials using the Client
27// RequestTemporaryCredentials method. The callbackURL parameter is the URL of
28// the callback handler in step 4. Save the returned credential secret so that
29// it can be later found using credential token as a key. The secret can be
30// stored in a database keyed by the token. Another option is to store the
31// token and secret in session storage or a cookie.
32//
33// Step 3: Redirect the user to URL returned from AuthorizationURL method. The
34// AuthorizationURL method uses the temporary credentials from step 2 and other
35// parameters as specified by the server.
36//
37// Step 4: The server redirects back to the callback URL specified in step 2
38// with the temporary token and a verifier. Use the temporary token to find the
39// temporary secret saved in step 2. Using the temporary token, temporary
40// secret and verifier, request token credentials using the client RequestToken
41// method. Save the returned credentials for later use in the application.
42//
43// Signing Requests
44//
45// The Client type has two low-level methods for signing requests, SignForm and
46// SetAuthorizationHeader.
47//
48// The SignForm method adds an OAuth signature to a form. The application makes
49// an authenticated request by encoding the modified form to the query string
50// or request body.
51//
52// The SetAuthorizationHeader method adds an OAuth siganture to a request
53// header. The SetAuthorizationHeader method is the only way to correctly sign
54// a request if the application sets the URL Opaque field when making a
55// request.
56//
57// The Get, Put, Post and Delete methods sign and invoke a request using the
58// supplied net/http Client. These methods are easy to use, but not as flexible
59// as constructing a request using one of the low-level methods.
60//
61// Context With HTTP Client
62//
63// A context-enabled method can include a custom HTTP client in the
64// context and execute an HTTP request using the included HTTP client.
65//
66//     hc := &http.Client{Timeout: 2 * time.Second}
67//     ctx := context.WithValue(context.Background(), oauth.HTTPClient, hc)
68//     c := oauth.Client{ /* Any settings */ }
69//     resp, err := c.GetContext(ctx, &oauth.Credentials{}, rawurl, nil)
70package oauth // import "github.com/garyburd/go-oauth/oauth"
71
72import (
73	"bytes"
74	"crypto"
75	"crypto/hmac"
76	"crypto/rand"
77	"crypto/rsa"
78	"crypto/sha1"
79	"encoding/base64"
80	"encoding/binary"
81	"errors"
82	"fmt"
83	"io"
84	"io/ioutil"
85	"net/http"
86	"net/url"
87	"sort"
88	"strconv"
89	"strings"
90	"sync/atomic"
91	"time"
92
93	"golang.org/x/net/context"
94)
95
96// noscape[b] is true if b should not be escaped per section 3.6 of the RFC.
97var noEscape = [256]bool{
98	'A': true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
99	'a': true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
100	'0': true, true, true, true, true, true, true, true, true, true,
101	'-': true,
102	'.': true,
103	'_': true,
104	'~': true,
105}
106
107// encode encodes string per section 3.6 of the RFC. If double is true, then
108// the encoding is applied twice.
109func encode(s string, double bool) []byte {
110	// Compute size of result.
111	m := 3
112	if double {
113		m = 5
114	}
115	n := 0
116	for i := 0; i < len(s); i++ {
117		if noEscape[s[i]] {
118			n++
119		} else {
120			n += m
121		}
122	}
123
124	p := make([]byte, n)
125
126	// Encode it.
127	j := 0
128	for i := 0; i < len(s); i++ {
129		b := s[i]
130		if noEscape[b] {
131			p[j] = b
132			j++
133		} else if double {
134			p[j] = '%'
135			p[j+1] = '2'
136			p[j+2] = '5'
137			p[j+3] = "0123456789ABCDEF"[b>>4]
138			p[j+4] = "0123456789ABCDEF"[b&15]
139			j += 5
140		} else {
141			p[j] = '%'
142			p[j+1] = "0123456789ABCDEF"[b>>4]
143			p[j+2] = "0123456789ABCDEF"[b&15]
144			j += 3
145		}
146	}
147	return p
148}
149
150type keyValue struct{ key, value []byte }
151
152type byKeyValue []keyValue
153
154func (p byKeyValue) Len() int      { return len(p) }
155func (p byKeyValue) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
156func (p byKeyValue) Less(i, j int) bool {
157	sgn := bytes.Compare(p[i].key, p[j].key)
158	if sgn == 0 {
159		sgn = bytes.Compare(p[i].value, p[j].value)
160	}
161	return sgn < 0
162}
163
164func (p byKeyValue) appendValues(values url.Values) byKeyValue {
165	for k, vs := range values {
166		k := encode(k, true)
167		for _, v := range vs {
168			v := encode(v, true)
169			p = append(p, keyValue{k, v})
170		}
171	}
172	return p
173}
174
175// writeBaseString writes method, url, and params to w using the OAuth signature
176// base string computation described in section 3.4.1 of the RFC.
177func writeBaseString(w io.Writer, method string, u *url.URL, form url.Values, oauthParams map[string]string) {
178	// Method
179	w.Write(encode(strings.ToUpper(method), false))
180	w.Write([]byte{'&'})
181
182	// URL
183	scheme := strings.ToLower(u.Scheme)
184	host := strings.ToLower(u.Host)
185
186	uNoQuery := *u
187	uNoQuery.RawQuery = ""
188	path := uNoQuery.RequestURI()
189
190	switch {
191	case scheme == "http" && strings.HasSuffix(host, ":80"):
192		host = host[:len(host)-len(":80")]
193	case scheme == "https" && strings.HasSuffix(host, ":443"):
194		host = host[:len(host)-len(":443")]
195	}
196
197	w.Write(encode(scheme, false))
198	w.Write(encode("://", false))
199	w.Write(encode(host, false))
200	w.Write(encode(path, false))
201	w.Write([]byte{'&'})
202
203	// Create sorted slice of encoded parameters. Parameter keys and values are
204	// double encoded in a single step. This is safe because double encoding
205	// does not change the sort order.
206	queryParams := u.Query()
207	p := make(byKeyValue, 0, len(form)+len(queryParams)+len(oauthParams))
208	p = p.appendValues(form)
209	p = p.appendValues(queryParams)
210	for k, v := range oauthParams {
211		p = append(p, keyValue{encode(k, true), encode(v, true)})
212	}
213	sort.Sort(p)
214
215	// Write the parameters.
216	encodedAmp := encode("&", false)
217	encodedEqual := encode("=", false)
218	sep := false
219	for _, kv := range p {
220		if sep {
221			w.Write(encodedAmp)
222		} else {
223			sep = true
224		}
225		w.Write(kv.key)
226		w.Write(encodedEqual)
227		w.Write(kv.value)
228	}
229}
230
231var nonceCounter uint64
232
233func init() {
234	if err := binary.Read(rand.Reader, binary.BigEndian, &nonceCounter); err != nil {
235		// fallback to time if rand reader is broken
236		nonceCounter = uint64(time.Now().UnixNano())
237	}
238}
239
240// nonce returns a unique string.
241func nonce() string {
242	return strconv.FormatUint(atomic.AddUint64(&nonceCounter, 1), 16)
243}
244
245// SignatureMethod identifies a signature method.
246type SignatureMethod int
247
248func (sm SignatureMethod) String() string {
249	switch sm {
250	case RSASHA1:
251		return "RSA-SHA1"
252	case HMACSHA1:
253		return "HMAC-SHA1"
254	case PLAINTEXT:
255		return "PLAINTEXT"
256	default:
257		return "unknown"
258	}
259}
260
261const (
262	HMACSHA1  SignatureMethod = iota // HMAC-SHA1
263	RSASHA1                          // RSA-SHA1
264	PLAINTEXT                        // Plain text
265)
266
267// Credentials represents client, temporary and token credentials.
268type Credentials struct {
269	Token  string // Also known as consumer key or access token.
270	Secret string // Also known as consumer secret or access token secret.
271}
272
273// Client represents an OAuth client.
274type Client struct {
275	// Credentials specifies the client key and secret.
276	// Also known as the consumer key and secret
277	Credentials Credentials
278
279	// TemporaryCredentialRequestURI is the endpoint used by the client to
280	// obtain a set of temporary credentials. Also known as the request token
281	// URL.
282	TemporaryCredentialRequestURI string
283
284	// ResourceOwnerAuthorizationURI is the endpoint to which the resource
285	// owner is redirected to grant authorization. Also known as authorization
286	// URL.
287	ResourceOwnerAuthorizationURI string
288
289	// TokenRequestURI is the endpoint used by the client to request a set of
290	// token credentials using a set of temporary credentials. Also known as
291	// access token URL.
292	TokenRequestURI string
293
294	// RenewCredentialRequestURI is the endpoint the client uses to
295	// request a new set of token credentials using the old set of credentials.
296	RenewCredentialRequestURI string
297
298	// TemporaryCredentialsMethod is the HTTP method used by the client to
299	// obtain a set of temporary credentials. If this field is the empty
300	// string, then POST is used.
301	TemporaryCredentialsMethod string
302
303	// TokenCredentailsMethod is the HTTP method used by the client to request
304	// a set of token credentials. If this field is the empty string, then POST
305	// is used.
306	TokenCredentailsMethod string
307
308	// Header specifies optional extra headers for requests.
309	Header http.Header
310
311	// SignatureMethod specifies the method for signing a request.
312	SignatureMethod SignatureMethod
313
314	// PrivateKey is the private key to use for RSA-SHA1 signatures. This field
315	// must be set for RSA-SHA1 signatures and ignored for other signature
316	// methods.
317	PrivateKey *rsa.PrivateKey
318}
319
320type request struct {
321	credentials   *Credentials
322	method        string
323	u             *url.URL
324	form          url.Values
325	verifier      string
326	sessionHandle string
327	callbackURL   string
328}
329
330var testHook = func(map[string]string) {}
331
332// oauthParams returns the OAuth request parameters for the given credentials,
333// method, URL and application params. See
334// http://tools.ietf.org/html/rfc5849#section-3.4 for more information about
335// signatures.
336func (c *Client) oauthParams(r *request) (map[string]string, error) {
337	oauthParams := map[string]string{
338		"oauth_consumer_key":     c.Credentials.Token,
339		"oauth_signature_method": c.SignatureMethod.String(),
340		"oauth_version":          "1.0",
341	}
342
343	if c.SignatureMethod != PLAINTEXT {
344		oauthParams["oauth_timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
345		oauthParams["oauth_nonce"] = nonce()
346	}
347
348	if r.credentials != nil {
349		oauthParams["oauth_token"] = r.credentials.Token
350	}
351
352	if r.verifier != "" {
353		oauthParams["oauth_verifier"] = r.verifier
354	}
355
356	if r.sessionHandle != "" {
357		oauthParams["oauth_session_handle"] = r.sessionHandle
358	}
359
360	if r.callbackURL != "" {
361		oauthParams["oauth_callback"] = r.callbackURL
362	}
363
364	testHook(oauthParams)
365
366	var signature string
367
368	switch c.SignatureMethod {
369	case HMACSHA1:
370		key := encode(c.Credentials.Secret, false)
371		key = append(key, '&')
372		if r.credentials != nil {
373			key = append(key, encode(r.credentials.Secret, false)...)
374		}
375		h := hmac.New(sha1.New, key)
376		writeBaseString(h, r.method, r.u, r.form, oauthParams)
377		signature = base64.StdEncoding.EncodeToString(h.Sum(key[:0]))
378	case RSASHA1:
379		if c.PrivateKey == nil {
380			return nil, errors.New("oauth: private key not set")
381		}
382		h := sha1.New()
383		writeBaseString(h, r.method, r.u, r.form, oauthParams)
384		rawSignature, err := rsa.SignPKCS1v15(rand.Reader, c.PrivateKey, crypto.SHA1, h.Sum(nil))
385		if err != nil {
386			return nil, err
387		}
388		signature = base64.StdEncoding.EncodeToString(rawSignature)
389	case PLAINTEXT:
390		rawSignature := encode(c.Credentials.Secret, false)
391		rawSignature = append(rawSignature, '&')
392		if r.credentials != nil {
393			rawSignature = append(rawSignature, encode(r.credentials.Secret, false)...)
394		}
395		signature = string(rawSignature)
396	default:
397		return nil, errors.New("oauth: unknown signature method")
398	}
399
400	oauthParams["oauth_signature"] = signature
401	return oauthParams, nil
402}
403
404// SignForm adds an OAuth signature to form. The urlStr argument must not
405// include a query string.
406//
407// See http://tools.ietf.org/html/rfc5849#section-3.5.2 for
408// information about transmitting OAuth parameters in a request body and
409// http://tools.ietf.org/html/rfc5849#section-3.5.2 for information about
410// transmitting OAuth parameters in a query string.
411func (c *Client) SignForm(credentials *Credentials, method, urlStr string, form url.Values) error {
412	u, err := url.Parse(urlStr)
413	switch {
414	case err != nil:
415		return err
416	case u.RawQuery != "":
417		return errors.New("oauth: urlStr argument to SignForm must not include a query string")
418	}
419	p, err := c.oauthParams(&request{credentials: credentials, method: method, u: u, form: form})
420	if err != nil {
421		return err
422	}
423	for k, v := range p {
424		form.Set(k, v)
425	}
426	return nil
427}
428
429// SignParam is deprecated. Use SignForm instead.
430func (c *Client) SignParam(credentials *Credentials, method, urlStr string, params url.Values) {
431	u, _ := url.Parse(urlStr)
432	u.RawQuery = ""
433	p, _ := c.oauthParams(&request{credentials: credentials, method: method, u: u, form: params})
434	for k, v := range p {
435		params.Set(k, v)
436	}
437}
438
439var oauthKeys = []string{
440	"oauth_consumer_key",
441	"oauth_nonce",
442	"oauth_signature",
443	"oauth_signature_method",
444	"oauth_timestamp",
445	"oauth_token",
446	"oauth_version",
447	"oauth_callback",
448	"oauth_verifier",
449	"oauth_session_handle",
450}
451
452func (c *Client) authorizationHeader(r *request) (string, error) {
453	p, err := c.oauthParams(r)
454	if err != nil {
455		return "", err
456	}
457	var h []byte
458	// Append parameters in a fixed order to support testing.
459	for _, k := range oauthKeys {
460		if v, ok := p[k]; ok {
461			if h == nil {
462				h = []byte(`OAuth `)
463			} else {
464				h = append(h, ", "...)
465			}
466			h = append(h, k...)
467			h = append(h, `="`...)
468			h = append(h, encode(v, false)...)
469			h = append(h, '"')
470		}
471	}
472	return string(h), nil
473}
474
475// AuthorizationHeader returns the HTTP authorization header value for given
476// method, URL and parameters.
477//
478// AuthorizationHeader is deprecated. Use SetAuthorizationHeader instead.
479func (c *Client) AuthorizationHeader(credentials *Credentials, method string, u *url.URL, params url.Values) string {
480	// Signing a request can return an error. This method is deprecated because
481	// this method does not return an error.
482	v, _ := c.authorizationHeader(&request{credentials: credentials, method: method, u: u, form: params})
483	return v
484}
485
486// SetAuthorizationHeader adds an OAuth signature to a request header.
487//
488// See http://tools.ietf.org/html/rfc5849#section-3.5.1 for information about
489// transmitting OAuth parameters in an HTTP request header.
490func (c *Client) SetAuthorizationHeader(header http.Header, credentials *Credentials, method string, u *url.URL, form url.Values) error {
491	v, err := c.authorizationHeader(&request{credentials: credentials, method: method, u: u, form: form})
492	if err != nil {
493		return err
494	}
495	header.Set("Authorization", v)
496	return nil
497}
498
499func (c *Client) do(ctx context.Context, urlStr string, r *request) (*http.Response, error) {
500	var body io.Reader
501	if r.method != http.MethodGet {
502		body = strings.NewReader(r.form.Encode())
503	}
504	req, err := http.NewRequest(r.method, urlStr, body)
505	if err != nil {
506		return nil, err
507	}
508	if req.URL.RawQuery != "" {
509		return nil, errors.New("oauth: url must not contain a query string")
510	}
511	for k, v := range c.Header {
512		req.Header[k] = v
513	}
514	r.u = req.URL
515	auth, err := c.authorizationHeader(r)
516	if err != nil {
517		return nil, err
518	}
519	req.Header.Set("Authorization", auth)
520	if r.method == http.MethodGet {
521		req.URL.RawQuery = r.form.Encode()
522	} else {
523		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
524	}
525	req = requestWithContext(ctx, req)
526	client := contextClient(ctx)
527	return client.Do(req)
528}
529
530// Get issues a GET to the specified URL with form added as a query string.
531func (c *Client) Get(client *http.Client, credentials *Credentials, urlStr string, form url.Values) (*http.Response, error) {
532	ctx := context.WithValue(context.Background(), HTTPClient, client)
533	return c.GetContext(ctx, credentials, urlStr, form)
534}
535
536// GetContext uses Context to perform Get.
537func (c *Client) GetContext(ctx context.Context, credentials *Credentials, urlStr string, form url.Values) (*http.Response, error) {
538	return c.do(ctx, urlStr, &request{method: http.MethodGet, credentials: credentials, form: form})
539}
540
541// Post issues a POST with the specified form.
542func (c *Client) Post(client *http.Client, credentials *Credentials, urlStr string, form url.Values) (*http.Response, error) {
543	ctx := context.WithValue(context.Background(), HTTPClient, client)
544	return c.PostContext(ctx, credentials, urlStr, form)
545}
546
547// PostContext uses Context to perform Post.
548func (c *Client) PostContext(ctx context.Context, credentials *Credentials, urlStr string, form url.Values) (*http.Response, error) {
549	return c.do(ctx, urlStr, &request{method: http.MethodPost, credentials: credentials, form: form})
550}
551
552// Delete issues a DELETE with the specified form.
553func (c *Client) Delete(client *http.Client, credentials *Credentials, urlStr string, form url.Values) (*http.Response, error) {
554	ctx := context.WithValue(context.Background(), HTTPClient, client)
555	return c.DeleteContext(ctx, credentials, urlStr, form)
556}
557
558// DeleteContext uses Context to perform Delete.
559func (c *Client) DeleteContext(ctx context.Context, credentials *Credentials, urlStr string, form url.Values) (*http.Response, error) {
560	return c.do(ctx, urlStr, &request{method: http.MethodDelete, credentials: credentials, form: form})
561}
562
563// Put issues a PUT with the specified form.
564func (c *Client) Put(client *http.Client, credentials *Credentials, urlStr string, form url.Values) (*http.Response, error) {
565	ctx := context.WithValue(context.Background(), HTTPClient, client)
566	return c.PutContext(ctx, credentials, urlStr, form)
567}
568
569// PutContext uses Context to perform Put.
570func (c *Client) PutContext(ctx context.Context, credentials *Credentials, urlStr string, form url.Values) (*http.Response, error) {
571	return c.do(ctx, urlStr, &request{method: http.MethodPut, credentials: credentials, form: form})
572}
573
574func (c *Client) requestCredentials(ctx context.Context, u string, r *request) (*Credentials, url.Values, error) {
575	if r.method == "" {
576		r.method = http.MethodPost
577	}
578	resp, err := c.do(ctx, u, r)
579	if err != nil {
580		return nil, nil, err
581	}
582	p, err := ioutil.ReadAll(resp.Body)
583	resp.Body.Close()
584	if err != nil {
585		return nil, nil, RequestCredentialsError{StatusCode: resp.StatusCode, Header: resp.Header,
586			Body: p, msg: err.Error()}
587	}
588	if resp.StatusCode != 200 && resp.StatusCode != 201 {
589		return nil, nil, RequestCredentialsError{StatusCode: resp.StatusCode, Header: resp.Header,
590			Body: p, msg: fmt.Sprintf("OAuth server status %d, %s", resp.StatusCode, string(p))}
591	}
592	m, err := url.ParseQuery(string(p))
593	if err != nil {
594		return nil, nil, RequestCredentialsError{StatusCode: resp.StatusCode, Header: resp.Header,
595			Body: p, msg: err.Error()}
596	}
597	tokens := m["oauth_token"]
598	if len(tokens) == 0 || tokens[0] == "" {
599		return nil, nil, RequestCredentialsError{StatusCode: resp.StatusCode, Header: resp.Header,
600			Body: p, msg: "oauth: token missing from server result"}
601	}
602	secrets := m["oauth_token_secret"]
603	if len(secrets) == 0 { // allow "" as a valid secret.
604		return nil, nil, RequestCredentialsError{StatusCode: resp.StatusCode, Header: resp.Header,
605			Body: p, msg: "oauth: secret missing from server result"}
606	}
607	return &Credentials{Token: tokens[0], Secret: secrets[0]}, m, nil
608}
609
610// RequestTemporaryCredentials requests temporary credentials from the server.
611// See http://tools.ietf.org/html/rfc5849#section-2.1 for information about
612// temporary credentials.
613func (c *Client) RequestTemporaryCredentials(client *http.Client, callbackURL string, additionalParams url.Values) (*Credentials, error) {
614	ctx := context.WithValue(context.Background(), HTTPClient, client)
615	return c.RequestTemporaryCredentialsContext(ctx, callbackURL, additionalParams)
616}
617
618// RequestTemporaryCredentialsContext uses Context to perform RequestTemporaryCredentials.
619func (c *Client) RequestTemporaryCredentialsContext(ctx context.Context, callbackURL string, additionalParams url.Values) (*Credentials, error) {
620	credentials, _, err := c.requestCredentials(ctx, c.TemporaryCredentialRequestURI,
621		&request{method: c.TemporaryCredentialsMethod, form: additionalParams, callbackURL: callbackURL})
622	return credentials, err
623}
624
625// RequestToken requests token credentials from the server. See
626// http://tools.ietf.org/html/rfc5849#section-2.3 for information about token
627// credentials.
628func (c *Client) RequestToken(client *http.Client, temporaryCredentials *Credentials, verifier string) (*Credentials, url.Values, error) {
629	ctx := context.WithValue(context.Background(), HTTPClient, client)
630	return c.RequestTokenContext(ctx, temporaryCredentials, verifier)
631}
632
633// RequestTokenContext uses Context to perform RequestToken.
634func (c *Client) RequestTokenContext(ctx context.Context, temporaryCredentials *Credentials, verifier string) (*Credentials, url.Values, error) {
635	return c.requestCredentials(ctx, c.TokenRequestURI,
636		&request{credentials: temporaryCredentials, method: c.TokenCredentailsMethod, verifier: verifier})
637}
638
639// RenewRequestCredentials requests new token credentials from the server.
640// See http://wiki.oauth.net/w/page/12238549/ScalableOAuth#AccessTokenRenewal
641// for information about access token renewal.
642func (c *Client) RenewRequestCredentials(client *http.Client, credentials *Credentials, sessionHandle string) (*Credentials, url.Values, error) {
643	ctx := context.WithValue(context.Background(), HTTPClient, client)
644	return c.RenewRequestCredentialsContext(ctx, credentials, sessionHandle)
645}
646
647// RenewRequestCredentialsContext uses Context to perform RenewRequestCredentials.
648func (c *Client) RenewRequestCredentialsContext(ctx context.Context, credentials *Credentials, sessionHandle string) (*Credentials, url.Values, error) {
649	return c.requestCredentials(ctx, c.RenewCredentialRequestURI, &request{credentials: credentials, sessionHandle: sessionHandle})
650}
651
652// RequestTokenXAuth requests token credentials from the server using the xAuth protocol.
653// See https://dev.twitter.com/oauth/xauth for information on xAuth.
654func (c *Client) RequestTokenXAuth(client *http.Client, temporaryCredentials *Credentials, user, password string) (*Credentials, url.Values, error) {
655	ctx := context.WithValue(context.Background(), HTTPClient, client)
656	return c.RequestTokenXAuthContext(ctx, temporaryCredentials, user, password)
657}
658
659// RequestTokenXAuthContext uses Context to perform RequestTokenXAuth.
660func (c *Client) RequestTokenXAuthContext(ctx context.Context, temporaryCredentials *Credentials, user, password string) (*Credentials, url.Values, error) {
661	form := make(url.Values)
662	form.Set("x_auth_mode", "client_auth")
663	form.Set("x_auth_username", user)
664	form.Set("x_auth_password", password)
665	return c.requestCredentials(ctx, c.TokenRequestURI,
666		&request{credentials: temporaryCredentials, method: c.TokenCredentailsMethod, form: form})
667}
668
669// AuthorizationURL returns the URL for resource owner authorization. See
670// http://tools.ietf.org/html/rfc5849#section-2.2 for information about
671// resource owner authorization.
672func (c *Client) AuthorizationURL(temporaryCredentials *Credentials, additionalParams url.Values) string {
673	params := make(url.Values)
674	for k, vs := range additionalParams {
675		params[k] = vs
676	}
677	params.Set("oauth_token", temporaryCredentials.Token)
678	return c.ResourceOwnerAuthorizationURI + "?" + params.Encode()
679}
680
681// HTTPClient is the context key to use with context's
682// WithValue function to associate an *http.Client value with a context.
683var HTTPClient contextKey
684
685type contextKey struct{}
686
687func contextClient(ctx context.Context) *http.Client {
688	if ctx != nil {
689		if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok && hc != nil {
690			return hc
691		}
692	}
693	return http.DefaultClient
694}
695
696// RequestCredentialsError is an error containing
697// response information when requesting credentials.
698type RequestCredentialsError struct {
699	StatusCode int
700	Header     http.Header
701	Body       []byte
702	msg        string
703}
704
705func (e RequestCredentialsError) Error() string {
706	return e.msg
707}
708