oauth2

package module
Version: v0.0.0-...-1adb5ce Latest Latest
Warning

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

Go to latest
Published: Sep 3, 2015 License: Apache-2.0 Imports: 17 Imported by: 156

README

oauth2

Middleware oauth2 provides support of user login via an OAuth 2.0 backend for Macaron.

It currently support Google, GitHub, LinkedIn, Dropbox, Facebook, Weibo and QQ.

Usage

// ...
m.Use(oauth2.GitHub(oauth2.Options{
	ClientID:     "CLIENT_ID",
	ClientSecret: "CLIENT_SECRET",
	Scopes:       []string{"SCOPE"},
	PathLogin:    "/user/login/oauth2/github",
	PathCallback: "/user/login/github",
	RedirectURL:  "http://localhost:3000/user/login/github",
}))
// ...

Credits

This package is forked from golang/oauth2 and martini-contrib/oauth2 with modifications.

License

This project is under Apache v2 License. See the LICENSE file for the full license text.

Documentation

Overview

Package oauth2 is a middleware that provides support of user login via an OAuth 2.0 backend for Macaron.

Example (JWT)
package main

import (
	"log"
	"net/http"

	"github.com/macaron-contrib/oauth2"
)

func main() {
	opts, err := oauth2.New(
		// 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.
		oauth2.JWTClient(
			"xxx@developer.gserviceaccount.com",
			[]byte("-----BEGIN RSA PRIVATE KEY-----...")),
		oauth2.Scope("SCOPE1", "SCOPE2"),
		oauth2.JWTEndpoint("https://provider.com/o/oauth2/token"),
		// 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.
		// Subject is optional.
		oauth2.Subject("user@example.com"),
	)
	if err != nil {
		log.Fatal(err)
	}

	// Initiate an http.Client, the following GET request will be
	// authorized and authenticated on the behalf of user@example.com.
	client := http.Client{Transport: opts.NewTransport()}
	client.Get("...")
}
Output:

Example (Regular)
package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/macaron-contrib/oauth2"
)

func main() {
	opts, err := oauth2.New(
		oauth2.Client("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET"),
		oauth2.RedirectURL("YOUR_REDIRECT_URL"),
		oauth2.Scope("SCOPE1", "SCOPE2"),
		oauth2.Endpoint(
			"https://provider.com/o/oauth2/auth",
			"https://provider.com/o/oauth2/token",
		),
	)
	if err != nil {
		log.Fatal(err)
	}

	// Redirect user to consent page to ask for permission
	// for the scopes specified above.
	url := opts.AuthCodeURL("state", "online", "auto")
	fmt.Printf("Visit the URL for the auth dialog: %v", url)

	// Use the authorization code that is pushed to the redirect URL.
	// NewTransportWithCode will do the handshake to retrieve
	// an access token and initiate a Transport that is
	// authorized and authenticated by the retrieved token.
	var code string
	if _, err = fmt.Scan(&code); err != nil {
		log.Fatal(err)
	}
	t, err := opts.NewTransportFromCode(code)
	if err != nil {
		log.Fatal(err)
	}

	// You can use t to initiate a new http.Client and
	// start making authenticated requests.
	client := http.Client{Transport: t}
	client.Get("...")
}
Output:

Index

Examples

Constants

View Source
const (
	KEY_TOKEN     = "oauth2_token"
	KEY_NEXT_PAGE = "next"
)

Variables

View Source
var (
	AppSubUrl string
	// PathLogin is the path to handle OAuth 2.0 logins.
	PathLogin = "/login"
	// PathLogout is the path to handle OAuth 2.0 logouts.
	PathLogout = "/logout"
	// PathCallback is the path to handle callback from OAuth 2.0 backend
	// to exchange credentials.
	PathCallback = "/oauth2callback"
	// PathError is the path to handle error cases.
	PathError = "/oauth2error"
)
View Source
var LoginRequired macaron.Handler = func() macaron.Handler {
	return func(ctx *macaron.Context, s session.Store) {
		token := unmarshallToken(s)
		if token == nil || token.Expired() {
			next := url.QueryEscape(ctx.Req.URL.RequestURI())
			ctx.Redirect(PathLogin + "?next=" + next)
		}
	}
}()

Handler that redirects user to the login page if user is not logged in. Sample usage: m.Get("/login-required", oauth2.LoginRequired, func() ... {})

Functions

func Dropbox

func Dropbox(opt Options) macaron.Handler

func Facebook

func Facebook(opt Options) macaron.Handler

func GitHub

func GitHub(opt Options) macaron.Handler

GitHub returns a new Github OAuth 2.0 backend endpoint.

func Google

func Google(opt Options) macaron.Handler

Google returns a new Google OAuth 2.0 backend endpoint.

func LinkedIn

func LinkedIn(opt Options) macaron.Handler

func NewOAuth2Provider

func NewOAuth2Provider(option Options, authURL, tokenURL string) macaron.Handler

NewOAuth2Provider returns a generic OAuth 2.0 backend endpoint.

func ParseKey

func ParseKey(key []byte) (*rsa.PrivateKey, error)

ParseKey converts the binary contents of a private key file to an *rsa.PrivateKey. It detects whether the private key is in a PEM container or not. If so, it extracts the the private key from PEM container before conversion. It only supports PEM containers with no passphrase.

func Tencent

func Tencent(opt Options) macaron.Handler

func Weibo

func Weibo(opt Options) macaron.Handler

Types

type Options

type Options struct {
	// ClientID is the OAuth client identifier used when communicating with
	// the configured OAuth provider.
	ClientID string

	// ClientSecret is the OAuth client secret used when communicating with
	// the configured OAuth provider.
	ClientSecret string

	PathLogin    string
	PathLogout   string
	PathCallback string

	// RedirectURL is the URL to which the user will be returned after
	// granting (or denying) access.
	RedirectURL string

	// Email is the OAuth client identifier used when communicating with
	// the configured OAuth provider.
	Email string

	// PrivateKey contains the contents of an RSA private key or the
	// contents of a PEM file that contains a private key. The provided
	// private key is used to sign JWT payloads.
	// PEM containers with a passphrase are not supported.
	// Use the following command to convert a PKCS 12 file into a PEM.
	//
	//    $ openssl pkcs12 -in key.p12 -out key.pem -nodes
	//
	PrivateKey *rsa.PrivateKey

	// Scopes identify the level of access being requested.
	Subject string

	// Scopes optionally specifies a list of requested permission scopes.
	Scopes []string

	// AuthURL represents the authorization endpoint of the OAuth 2.0 provider.
	AuthURL *url.URL

	// TokenURL represents the token endpoint of the OAuth 2.0 provider.
	TokenURL *url.URL

	// AUD represents the token endpoint required to complete the 2-legged JWT flow.
	AUD *url.URL

	// TokenStore reads a token from the store and writes it back to the store
	// if a token refresh occurs.
	// Optional.
	TokenStore TokenStore

	TokenFetcherFunc func(t *Token) (*Token, error)

	Client *http.Client
}

Options represents an object to keep the state of the OAuth 2.0 flow.

func New

func New(opt *Options) (*Options, error)

New builds a new options object and determines the type of the OAuth 2.0 (2-legged, 3-legged or custom) by looking at the provided options. If the flow type cannot determined automatically, an error is returned.

func (*Options) AuthCodeURL

func (o *Options) AuthCodeURL(state, accessType, prompt string) 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.

Access type is an OAuth extension that gets sent as the "access_type" field in the URL from AuthCodeURL. It may be "online" (default) or "offline". If your application needs to refresh access tokens when the user is not present at the browser, then use offline. This will result in your application obtaining a refresh token the first time your application exchanges an authorization code for a user.

Approval prompt indicates whether the user should be re-prompted for consent. If set to "auto" (default) the user will be prompted only if they haven't previously granted consent and the code can only be exchanged for an access token. If set to "force" the user will always be prompted, and the code can be exchanged for a refresh token.

func (*Options) NewTransport

func (o *Options) NewTransport() *Transport

NewTransport returns a Transport.

func (*Options) NewTransportFromCode

func (o *Options) NewTransportFromCode(code string) (*Transport, error)

NewTransportFromCode exchanges the code to retrieve a new access token and returns an authorized and authenticated Transport.

func (*Options) NewTransportFromToken

func (o *Options) NewTransportFromToken(t *Token) *Transport

newTransportFromToken returns a new Transport that is authorized and authenticated with the provided token.

func (*Options) NewTransportFromTokenStore

func (o *Options) NewTransportFromTokenStore(store TokenStore) (*Transport, error)

NewTransportFromTokenStore reads the token from the store and returns a Transport that is authorized and the authenticated by the returned token.

type Token

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

	// Identifies the type of token returned.
	TokenType string `json:"token_type,omitempty"`

	// A token that may be used to obtain a new access token.
	RefreshToken string `json:"refresh_token,omitempty"`

	// The remaining lifetime of the access token.
	Expiry time.Time `json:"expiry,omitempty"`

	// Raw optionally contains extra metadata from the server
	// when updating a token.
	Raw interface{}
}

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

func (*Token) Expired

func (t *Token) Expired() bool

Expired returns true if there is no access token or the access token is expired.

func (*Token) Extra

func (t *Token) Extra(key string) string

Extra returns an extra field returned from the server during token retrieval. E.g.

idToken := token.Extra("id_token")

type TokenStore

type TokenStore interface {
	// ReadToken reads the token from the store.
	// If the read is successful, it should return the token and a nil error.
	// The returned tokens may be expired tokens.
	// If there is no token in the store, it should return a nil token and a nil error.
	// It should return a non-nil error when an unrecoverable failure occurs.
	ReadToken() (*Token, error)
	// WriteToken writes the token to the cache.
	WriteToken(*Token)
}

TokenStore implementations read and write OAuth 2.0 tokens from a persistence layer.

type Tokens

type Tokens interface {
	Access() string
	Refresh() string
	Expired() bool
	ExpiryTime() time.Time
	Extra(string) string
}

Tokens represents a container that contains user's OAuth 2.0 access and refresh tokens.

type Transport

type Transport struct {
	// contains filtered or unexported fields
}

Transport is an http.RoundTripper that makes OAuth 2.0 HTTP requests.

func (*Transport) Client

func (t *Transport) Client() *http.Client

Client returns an *http.Client that makes OAuth-authenticated requests.

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, tries to refresh/fetch a new token.

func (*Transport) Token

func (t *Transport) Token() *Token

Token returns the token that authorizes and authenticates the transport.

Directories

Path Synopsis
Package jws provides encoding and decoding utilities for signed JWS messages.
Package jws provides encoding and decoding utilities for signed JWS messages.

Jump to

Keyboard shortcuts

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