oauth2

package module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2022 License: BSD-3-Clause Imports: 16 Imported by: 14

README

OAuth2 for Go

GoDoc

oauth2 package is forked from golang.org/x/oauth2. The major change is the handling of contexts. Context for requesting tokens is taken from the http.request rather than stored in the TokenSource. This allows for a TokenSource to exist accross contexts and, when wrapped by ReuseTokenSource func, to be safe for concurrent use.

The IDSecretInBody flag is added to the endpoint definition to replace "brokenAuthHeaderProviders" logic.

Issues that are resolved in this implementation includ

https://github.com/golang/oauth2/issues/223 all: find a better way to set a custom HTTP client

https://github.com/golang/oauth2/issues/262 TokenSource. Token method should take in a Context

https://github.com/golang/oauth2/issues/198 google: no way to set jws.PrivateClaims (needed for Firebase)

https://github.com/golang/oauth2/issues/198 Token expiration tolerance should be configurable #249

https://github.com/golang/oauth2/issues/256 OAuth2: Ability to specify "audience" parameter to token refresh #256

https://github.com/golang/oauth2/issues/84 CacheToken/transport confusion

Installation

go get github.com/jfcote87/oauth2

Documentation

Overview

Package oauth2 provides support for making OAuth2 authorized and authenticated HTTP requests. It can additionally grant authorization with Bearer JWT.

Example (DefaultClient)
package main

import (
	"log"

	"github.com/jfcote87/oauth2"
	"github.com/jfcote87/oauth2/google"
)

func main() {
	client, err := google.DefaultClient(oauth2.NoContext,
		"https://www.googleapis.com/auth/devstorage.full_control")
	if err != nil {
		log.Fatal(err)
	}
	client.Get("...")
}
Output:

Example (GoogleComputeTokenSource)
package main

import (
	"net/http"

	"github.com/jfcote87/oauth2"
	"github.com/jfcote87/oauth2/google"
)

func main() {
	client := &http.Client{
		Transport: &oauth2.Transport{
			// Fetch from Google Compute Engine's metadata server to retrieve
			// an access token for the provided account.
			// If no account is specified, "default" is used.
			Source: google.ComputeTokenSource(""),
		},
	}
	client.Get("...")
}
Output:

Example (GoogleServiceAccount)
package main

import (
	"log"

	"github.com/jfcote87/oauth2/google"
	"github.com/jfcote87/oauth2/jws"
	"github.com/jfcote87/oauth2/jwt"
)

func main() { // The contents of your RSA private key or your PEM file
	// that contains a private key.
	// If you have a p12 file instead, you
	// can use `openssl` to export the private key into a pem file.
	//
	//    $ openssl pkcs12 -in key.p12 -out key.pem -nodes
	//
	// It only supports PEM containers with no passphrase.
	signer, err := jws.RS256FromPEM([]byte("-----BEGIN RSA PRIVATE KEY-----..."), "")
	if err != nil {
		log.Fatalf("Invalid key: %v", err)
	}
	// Your credentials should be obtained from the Google
	// Developer Console (https://console.developers.google.com).
	conf := &jwt.Config{
		Signer: signer,
		Issuer: "xxx@developer.gserviceaccount.com",
		Scopes: []string{
			"https://www.googleapis.com/auth/bigquery",
			"https://www.googleapis.com/auth/blogger",
		},
		TokenURL: google.JWTTokenURL,
		Audience: google.JWTTokenURL,
		// If you would like to impersonate a user, you can
		// create a transport with a subject. The following GET
		// request will be made on the behalf of user@example.com.
		// Optional.
		Subject: "user@example.com",
	}
	// Initiate an http.Client, the following GET request will be
	// authorized and authenticated on the behalf of user@example.com.
	client, _ := conf.Client(nil)
	client.Get("...")
}
Output:

Example (JWTConfigFromJSON)
package main

import (
	"io/ioutil"
	"log"

	"github.com/jfcote87/oauth2/google"
)

func main() {
	// Your credentials should be obtained from the Google
	// Developer Console (https://console.developers.google.com).
	// Navigate to your project, then see the "Credentials" page
	// under "APIs & Auth".
	// To create a service account client, click "Create new Client ID",
	// select "Service Account", and click "Create Client ID". A JSON
	// key file will then be downloaded to your computer.
	data, err := ioutil.ReadFile("/path/to/your-project-key.json")
	if err != nil {
		log.Fatal(err)
	}
	conf, err := google.JWTConfigFromJSON(data, "https://www.googleapis.com/auth/bigquery")
	if err != nil {
		log.Fatal(err)
	}
	// Initiate an http.Client. The following GET request will be
	// authorized and authenticated on the behalf of
	// your service account.
	client, _ := conf.Client(nil)
	client.Get("...")
}
Output:

Example (SDKConfig)
package main

import (
	"log"

	"github.com/jfcote87/oauth2/google"
)

func main() {
	// The credentials will be obtained from the first account that
	// has been authorized with `gcloud auth login`.
	conf, err := google.NewSDKConfig("")
	if err != nil {
		log.Fatal(err)
	}
	// Initiate an http.Client. The following GET request will be
	// authorized and authenticated on the behalf of the SDK user.
	conf.Client().Get("...")
}
Output:

Example (WebServer)
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/jfcote87/oauth2"
	"github.com/jfcote87/oauth2/google"
)

func main() {
	// Your credentials should be obtained from the Google
	// Developer Console (https://console.developers.google.com).
	conf := &oauth2.Config{
		ClientID:     "YOUR_CLIENT_ID",
		ClientSecret: "YOUR_CLIENT_SECRET",
		RedirectURL:  "YOUR_REDIRECT_URL",
		Scopes: []string{
			"https://www.googleapis.com/auth/bigquery",
			"https://www.googleapis.com/auth/blogger",
		},
		Endpoint: google.Endpoint,
	}
	// Redirect user to Google's consent page to ask for permission
	// for the scopes specified above.
	url := conf.AuthCodeURL("state")
	fmt.Printf("Visit the URL for the auth dialog: %v", url)
	cxx := context.Background()
	_ = cxx

	// Handle the exchange code to initiate a transport.
	tok, err := conf.Exchange(oauth2.NoContext, "authorization-code")
	if err != nil {
		log.Fatal(err)
	}
	client := conf.Client(tok)
	client.Get("...")
}
Output:

Index

Examples

Constants

View Source
const DefaultExpiryDelta int64 = 10

DefaultExpiryDelta determines the number of seconds a token should expire sooner than the delivered expiration time. This avoids late expirations due to client-server time mismatches and latency.

Variables

View Source
var (
	// AccessTypeOnline and AccessTypeOffline are options passed
	// to the Options.AuthCodeURL method. They modify the
	// "access_type" field that gets sent in the URL returned by
	// AuthCodeURL.
	//
	// Online is the default if neither is specified.
	AccessTypeOnline = SetAuthURLParam("access_type", "online")
	// AccessTypeOffline is used an application needs to refresh
	// access tokens when the user is not present. This will
	// result in your application obtaining a refresh token the
	// first time your application exchanges an authorization
	// code for a user.
	AccessTypeOffline = SetAuthURLParam("access_type", "offline")

	// ApprovalForce forces the users to view the consent dialog
	// and confirm the permissions request at the URL returned
	// from AuthCodeURL, even if they've already done so.
	ApprovalForce = SetAuthURLParam("prompt", "consent")
)
View Source
var NoContext = context.Background()

NoContext is the default background context

Functions

func Client

func Client(ts TokenSource, f ctxclient.Func) *http.Client

Client creates a client that sets an authorization header based on tokens created by the ctxtokensource ts.

Types

type AuthCodeOption

type AuthCodeOption interface {
	// contains filtered or unexported methods
}

An AuthCodeOption is passed to Config.AuthCodeURL.

func SetAuthURLParam

func SetAuthURLParam(key, value string) AuthCodeOption

SetAuthURLParam builds an AuthCodeOption which passes key/value parameters to a provider's authorization endpoint.

type Config

type Config struct {
	// ClientID is the application's ID.
	ClientID string

	// ClientSecret is the application's secret.
	ClientSecret string

	// Endpoint contains the resource server's token endpoint
	// URLs. These are constants specific to each server
	// implementation so please refer to vendor documentation.
	// I have no intentions of maintaining a list of public endpoints.
	Endpoint Endpoint

	// RedirectURL is the URL to redirect users going through
	// the OAuth flow, after the resource owner's URLs.
	RedirectURL string

	// Scope specifies optional requested permissions.
	Scopes []string

	// ExpiryDelta determines how many seconds sooner a token should
	// expire than the retrieved expires_in setting.
	ExpiryDelta int64

	// HTTPClientFunc may be set to determine the *http.Client
	// used for Exchange and Refresh calls.  If not set, the default
	// for appengine applications is created via the urlfetch.Client
	// function.  Otherwise the http.DefaultClient is assumed.
	HTTPClientFunc ctxclient.Func
}

Config describes a typical 3-legged OAuth2 flow, with both the client application information and the server's endpoint URLs. For the client credentials 2-legged OAuth2 flow, see the clientcredentials package (https://github.com/jfcote87/oauth2/clientcredentials).

func (*Config) AuthCodeURL

func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string

AuthCodeURL returns a URL to OAuth 2.0 provider's consent page that asks for permissions for the required scopes explicitly.

State is a token to protect the user from CSRF attacks. You must always provide a non-zero string and validate that it matches the the state query parameter on your redirect callback. See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.

Opts may include AccessTypeOnline or AccessTypeOffline, as well as ApprovalForce.

func (*Config) Client

func (c *Config) Client(t *Token) *http.Client

Client returns an HTTP client using the provided token. The token will auto-refresh as necessary. The underlying Client returns an HTTP client using the provided token. HTTP transport will be obtained using Config.HTTPClient. The returned client and its Transport should not be modified.

The returned client uses the request's context to handle timeouts and cancellations. It may be used concurrently as the token refresh is protected

func (*Config) Exchange

func (c *Config) Exchange(ctx context.Context, code string, opts ...AuthCodeOption) (*Token, error)

Exchange converts an authorization code into a token.

It is used after a resource provider redirects the user back to the Redirect URI (the URL obtained from AuthCodeURL).

The HTTP client to use is derived from the context. If a client is not provided via the context, http.DefaultClient is used.

The code will be in the *http.Request.FormValue("code"). Before calling Exchange, be sure to validate FormValue("state").

func (*Config) FromOptions

func (c *Config) FromOptions(opts ...AuthCodeOption) TokenSource

FromOptions returns a TokenSource that retrieves tokens using the parameters defined in opts. Used by clientcredentials package.

func (*Config) RefreshToken

func (c *Config) RefreshToken(ctx context.Context, refreshToken string, opts ...AuthCodeOption) (*Token, error)

RefreshToken retrieves a Token. A developer may use this to construct custom caching TokenSources.

func (*Config) TokenSource

func (c *Config) TokenSource(t *Token, opts ...AuthCodeOption) TokenSource

TokenSource returns a TokenSource that returns t until t expires, automatically refreshing it as necessary. This tokensource is safe for use with different contexts. opts

type Endpoint

type Endpoint struct {
	AuthURL  string
	TokenURL string
	// Set to true if server requires ClientID and Secret
	// in body rather than Basic Authentication.
	IDSecretInBody bool
}

Endpoint contains the OAuth 2.0 provider's authorization and token endpoint URLs.

type PerRPCCredentials

type PerRPCCredentials struct {
	TokenSource
}

PerRPCCredentials fulfills the grpc PerRPCCredentials interface allowing a developer to use a Tokensource for authorization.

 target := "firestore.googleapis.com:443"
 ctx := context.Background()
 ts, err := getTokensourceFromFile("/path/to/your-project-key.json",
		"https://www.googleapis.com/auth/datastore", "https://www.googleapis.com/auth/cloud-platform")
	if err != nil {
		log.Fatalf("%v", err)
	}
	conn, err := grpc.DialContext(ctx, target,
		grpc.WithPerRPCCredentials(&oauth2.PerRPCCredentials{
			TokenSource: ts,
		}),
		grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, "")),
	)
	conn.WaitForStateChange(ctx, connectivity.Ready)
	cl, err := firestore.NewClient(ctx, "my-firestore-project", option.WithGRPCConn(conn))
	if err != nil {
		log.Fatalf("%v", err)
	}

func (*PerRPCCredentials) GetRequestMetadata

func (c *PerRPCCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)

GetRequestMetadata returns authorization headers for a grpc credential

func (*PerRPCCredentials) RequireTransportSecurity

func (c *PerRPCCredentials) RequireTransportSecurity() bool

RequireTransportSecurity needed for google.golang.org/grpc/credential

type Token

type Token struct {
	// AccessToken is the token that authorizes and authenticates
	// the requests.
	AccessToken string `json:"access_token"`

	// TokenType is the type of token.
	// The Type method returns either this or "Bearer", the default.
	TokenType string `json:"token_type,omitempty"`

	// RefreshToken is a token that's used by the application
	// (as opposed to the user) to refresh the access token
	// if it expires.
	RefreshToken string `json:"refresh_token,omitempty"`

	// Expiry is the optional expiration time of the access token.
	//
	// If zero, TokenSource implementations will reuse the same
	// token forever and RefreshToken or equivalent
	// mechanisms for that TokenSource will not be used.
	Expiry time.Time `json:"expiry,omitempty"`
	// contains filtered or unexported fields
}

Token represents the crendentials used to authorize the requests to access protected resources on the OAuth 2.0 provider's backend.

Most users of this package should not access fields of Token directly. They're exported mostly for use by related packages implementing derivative OAuth2 flows.

func TokenFromMap added in v0.2.0

func TokenFromMap(vals map[string]interface{}, expiryDelta time.Duration) (*Token, error)

TokenFromMap create a *Token from a map[string]interface{}. Expect the access_token, refresh_token and token_type values to be strings, expires_in may be string or a type convertible to int64.

func (*Token) Extra

func (t *Token) Extra(key string) interface{}

Extra returns an extra field. Extra fields are key-value pairs returned by the server as a part of the token retrieval response.

func (*Token) SetAuthHeader

func (t *Token) SetAuthHeader(r *http.Request)

SetAuthHeader sets the Authorization header to r using the access token in t.

This method is unnecessary when using Transport or an HTTP Client returned by this package.

func (*Token) Type

func (t *Token) Type() string

Type returns t.TokenType if non-empty, else "Bearer".

func (*Token) Valid

func (t *Token) Valid() bool

Valid reports whether t is non-nil, has an AccessToken, and is not expired.

func (*Token) WithExtra

func (t *Token) WithExtra(extra interface{}) *Token

WithExtra returns a new Token that's a clone of t, but using the provided raw extra map. This is only intended for use by packages implementing derivative OAuth2 flows.

type TokenSource

type TokenSource interface {
	// Token returns a token or an error.
	// Token must be safe for concurrent use by multiple goroutines.
	// The returned Token must not be modified.
	Token(context.Context) (*Token, error)
}

A TokenSource is anything that can return a token. This package uses the passed context to determine/construct the appropriate http.Client for retrieving tokens and to allow for cancellation and timeouts of the Token request.

func ReuseTokenSource

func ReuseTokenSource(t *Token, src TokenSource) TokenSource

ReuseTokenSource returns a TokenSource which repeatedly returns the same token as long as it's valid, starting with t. When its cached token is invalid, a new token is obtained from src.

ReuseTokenSource is typically used to reuse tokens from a cache (such as a file on disk) between runs of a program, rather than obtaining new tokens unnecessarily.

The initial token t may be nil, in which case the TokenSource is wrapped in a caching version if it isn't one already. This also means it's always safe to wrap ReuseTokenSource around any other TokenSource without adverse effects.

ReuseTokenSource uses a mutex to allow the returned TokenSource to be used concurrently.

func StaticTokenSource

func StaticTokenSource(t *Token) TokenSource

StaticTokenSource returns a TokenSource that always returns the same token. Because the provided token t is never refreshed, StaticTokenSource is only useful for tokens that never expire.

type Transport

type Transport struct {
	// Source supplies the token to add to outgoing requests'
	// Authorization headers.
	Source TokenSource
	ctxclient.Func
}

Transport is an http.RoundTripper that makes OAuth 2.0 HTTP requests, wrapping a base RoundTripper and adding an Authorization header with a token from the supplied Sources.

Transport is a low-level mechanism. Most code will use the higher-level Config.Client method instead.

func (*Transport) RoundTrip

func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip authorizes and authenticates the request with an access token. If no token exists or token is expired, it fetches a new token passing along the request's context.

Directories

Path Synopsis
Package cache defines the Credentials tokensource which allows caching of oauth2 tokens
Package cache defines the Credentials tokensource which allows caching of oauth2 tokens
Package clientcredentials implements the OAuth2.0 "client credentials" token flow, also known as the "two-legged OAuth 2.0".
Package clientcredentials implements the OAuth2.0 "client credentials" token flow, also known as the "two-legged OAuth 2.0".
Package google provides support for making OAuth2 authorized and authenticated HTTP requests to Google APIs.
Package google provides support for making OAuth2 authorized and authenticated HTTP requests to Google APIs.
metadata
Package metadata provides access to Google Compute Engine (GCE) metadata and API service accounts.
Package metadata provides access to Google Compute Engine (GCE) metadata and API service accounts.
Package jws provides a partial implementation of JSON Web Signature encoding and decoding.
Package jws provides a partial implementation of JSON Web Signature encoding and decoding.
Package jwt implements the OAuth 2.0 JSON Web Token flow, commonly known as "two-legged OAuth 2.0".
Package jwt implements the OAuth 2.0 JSON Web Token flow, commonly known as "two-legged OAuth 2.0".

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL