diff --git a/README.md b/README.md index e69de29..4993caf 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,28 @@ +# OAuth2 for Go + +oauth2 package contains a client implementation for OAuth 2.0 spec. + +## Installation + +~~~~ +go get github.com/golang/oauth2 +~~~~ + +See [godoc](http://godoc.org/github.com/golang/oauth2) for further documentation and examples. + +## Contributing + +Fork the repo, make changes, run the tests and open a pull request. + +Before we can accept any pull requests +we have to jump through a couple of legal hurdles, +primarily a Contributor License Agreement (CLA): + +- **If you are an individual writing original source code** + and you're sure you own the intellectual property, + then you'll need to sign an [individual CLA](http://code.google.com/legal/individual-cla-v1.0.html). +- **If you work for a company that wants to allow you to contribute your work**, + then you'll need to sign a [corporate CLA](http://code.google.com/legal/corporate-cla-v1.0.html). + +You can sign these electronically (just scroll to the bottom). +After that, we'll be able to accept your pull requests. diff --git a/example_test.go b/example_test.go new file mode 100644 index 0000000..2b234ec --- /dev/null +++ b/example_test.go @@ -0,0 +1,112 @@ +package oauth2_test + +import ( + "fmt" + "log" + "net/http" + "testing" + + "github.com/golang/oauth2" +) + +// TODO(jbd): Remove after Go 1.4. +// Related to https://codereview.appspot.com/107320046 +func TestA(t *testing.T) {} + +func Example_config() { + conf, err := oauth2.NewConfig(&oauth2.Options{ + ClientID: "YOUR_CLIENT_ID", + ClientSecret: "YOUR_CLIENT_SECRET", + RedirectURL: "YOUR_REDIRECT_URL", + Scopes: []string{"SCOPE1", "SCOPE2"}, + }, + "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, err := conf.AuthCodeURL("") + if err != nil { + log.Fatal(err) + } + fmt.Printf("Visit the URL for the auth dialog: %v", url) + + // Use the exchange code that is handled by the redirect URL. + // NewTransportWithCode will do the handshake to retrieve + // an access token and iniate a Transport that is + // authorized and authenticated the retrieved token. + var exchangeCode string + if _, err = fmt.Scan(&exchangeCode); err != nil { + log.Fatal(err) + } + t, err := conf.NewTransportWithCode(exchangeCode) + 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("...") + + // Alternatively, you can initiate a new transport + // with tokens from a cache. + cache := oauth2.NewFileCache("/path/to/file") + // NewTransportWithCache will try to read the cached + // token, if any error occurs, it returns the error. + // If a token is available at the cache, initiates + // a new transport authorized and authenticated with + // the read token. If token expires, and a new access + // token is retrieved, it writes the newly fetched + // token to the cache. + t, err = conf.NewTransportWithCache(cache) + if err != nil { + log.Fatal(err) + } + client = http.Client{Transport: t} + client.Get("...") +} + +func Example_jWTConfig() { + conf, err := oauth2.NewJWTConfig(&oauth2.JWTOptions{ + Email: "xxx@developer.gserviceaccount.com", + // The path to the pem file. 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 + PemFilename: "/path/to/pem/file.pem", + Scopes: []string{"SCOPE1", "SCOPE2"}, + }, + "https://provider.com/o/oauth2/token") + if err != nil { + log.Fatal(err) + } + + // Initiate an http.Client, the following GET request will be + // authorized and authenticated on the behalf of + // xxx@developer.gserviceaccount.com. + client := http.Client{Transport: conf.NewTransport()} + client.Get("...") + + // 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. + client = http.Client{Transport: conf.NewTransportWithUser("user@example.com")} + client.Get("...") + + // Alternatively you can iniate a transport with + // a token read from the cache. + // If the existing access token expires, and a new access token is + // retrieved, the newly fetched token will be written to the cache. + cache := oauth2.NewFileCache("/path/to/file") + t, err := conf.NewTransportWithCache(cache) + if err != nil { + log.Fatal(err) + } + client = http.Client{Transport: t} + // The following request will be authorized by the token + // retrieved from the cache. + client.Get("...") +} diff --git a/google/example_test.go b/google/example_test.go new file mode 100644 index 0000000..be48c4d --- /dev/null +++ b/google/example_test.go @@ -0,0 +1,127 @@ +package google_test + +import ( + "fmt" + "log" + "net/http" + "testing" + + "github.com/golang/oauth2" + "github.com/golang/oauth2/google" + "google.golang.org/appengine" +) + +// Remove after Go 1.4. +// Related to https://codereview.appspot.com/107320046 +func TestA(t *testing.T) {} + +func Example_webServer() { + // Your credentials should be obtained from the Google + // Developer Console (https://console.developers.google.com). + config, err := google.NewConfig(&oauth2.Options{ + 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"}, + }) + if err != nil { + log.Fatal(err) + } + + // Redirect user to Google's consent page to ask for permission + // for the scopes specified above. + url, err := config.AuthCodeURL("") + if err != nil { + log.Fatal(err) + } + fmt.Printf("Visit the URL for the auth dialog: %v", url) + + // Handle the exchange code to initiate a transport + t, err := config.NewTransportWithCode("exchange-code") + if err != nil { + log.Fatal(err) + } + client := http.Client{Transport: t} + client.Get("...") + + // Alternatively you can initiate a new transport + // with a token from a cache. + cache := oauth2.NewFileCache("/path/to/file") + // NewTransportWithCache will try to read the cached + // token, if any error occurs, it returns the error. + // If a token is available at the cache, initiates + // a new transport authorized and authenticated with + // the read token. If token expires, and a new access + // token is retrieved, it writes the newly fetched + // token to the cache. + t, err = config.NewTransportWithCache(cache) + if err != nil { + log.Fatal(err) + } + client = http.Client{Transport: t} + client.Get("...") +} + +func Example_serviceAccounts() { + // Your credentials should be obtained from the Google + // Developer Console (https://console.developers.google.com). + config, err := google.NewServiceAccountConfig(&oauth2.JWTOptions{ + Email: "xxx@developer.gserviceaccount.com", + // The path to the pem file. 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 + PemFilename: "/path/to/pem/file.pem", + Scopes: []string{ + "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 + // xxx@developer.gserviceaccount.com. + client := http.Client{Transport: config.NewTransport()} + client.Get("...") + + // 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. + client = http.Client{Transport: config.NewTransportWithUser("user@example.com")} + client.Get("...") + + // Alternatively you can iniate a transport with + // a token read from the cache. + // If the existing access token expires, and a new access token is + // retrieved, the newly fetched token will be written to the cache. + cache := oauth2.NewFileCache("/path/to/file") + t, err := config.NewTransportWithCache(cache) + if err != nil { + log.Fatal(err) + } + client = http.Client{Transport: t} + // The following request will be authorized by the token + // retrieved from the cache. + client.Get("...") +} + +func Example_appEngine() { + context := appengine.NewContext(nil) + config := google.NewAppEngineConfig(context, []string{ + "https://www.googleapis.com/auth/bigquery", + }) + // The following client will be authorized by the App Engine + // app's service account for the provided scopes. + client := http.Client{Transport: config.NewTransport()} + client.Get("...") +} + +func Example_computeEngine() { + // If no other account is specified, "default" is used. + config := google.NewComputeEngineConfig("") + client := http.Client{Transport: config.NewTransport()} + client.Get("...") +} diff --git a/google/google.go b/google/google.go index 1b56433..fec36de 100644 --- a/google/google.go +++ b/google/google.go @@ -11,59 +11,6 @@ // // For more information, please read // https://developers.google.com/accounts/docs/OAuth2. -// -// Example usage: -// // Web server flow usage: -// // Specify your configuration. -// // Your credentials should be obtained from the Google -// // Developer Console (https://console.developers.google.com). -// var config = google.NewConfig(&oauth2.Opts{ -// ClientID: YOUR_CLIENT_ID, -// ClientSecret: YOUR_CLIENT_SECRET, -// RedirectURL: "http://you.example.org/handler", -// Scopes: []string{ "scope1", "scope2" }, -// }) -// -// // A landing page redirects to Google to get the auth code. -// func landing(w http.ResponseWriter, r *http.Request) { -// http.Redirect(w, r, config.AuthCodeURL(""), http.StatusFound) -// } -// -// // The user will be redirected back to this handler, that takes the -// // "code" query parameter and Exchanges it for an access token. -// func handler(w http.ResponseWriter, r *http.Request) { -// t, err := config.NewTransportWithCode(r.FormValue("code")) -// // The Transport now has a valid Token. Create an *http.Client -// // with which we can make authenticated API requests. -// c := t.Client() -// c.Post(...) -// } -// -// // Service accounts usage: -// // Google Developer Console will provide a p12 file contains -// // a private key. You need to export it to the pem format. -// // Run the following command to generate a pem file that -// // contains your private key: -// // $ openssl pkcs12 -in /path/to/p12key.p12 -out key.pem -nodes -// // Then, specify your configuration. -// var config = google.NewServiceAccountConfig(&oauth2.JWTOpts{ -// Email: "xxx@developer.gserviceaccount.com", -// PemFilename: "/path/to/key.pem", -// Scopes: []string{ -// "https://www.googleapis.com/auth/drive.readonly" -// }, -// }) -// -// // Create a transport. -// t, err := config.NewTransport() -// // Or, you can create a transport that impersonates -// // a Google user. -// t, err := config.NewTransportWithUser(googleUserEmail) -// -// // Create a client to make authorized requests. -// c := t.Client() -// c.Post(...) -// package google import ( diff --git a/oauth2.go b/oauth2.go index edfd75d..13119ef 100644 --- a/oauth2.go +++ b/oauth2.go @@ -5,32 +5,6 @@ // Package oauth2 provides support for making // OAuth2 authorized and authenticated HTTP requests. // It can additionally grant authorization with Bearer JWT. -// -// Example usage: -// -// // Specify your configuration. (typically as a global variable) -// config := oauth2.NewConfig(&oauth2.Options{ -// ClientID: YOUR_CLIENT_ID, -// ClientSecret: YOUR_CLIENT_SECRET, -// RedirectURL: "http://you.example.org/handler", -// Scopes: []string{ "scope1", "scope2" }, -// }, OAUTH2_PROVIDER_AUTH_URL, OAUTH2_PROVIDER_TOKEN_URL) -// -// // A landing page redirects to the OAuth provider to get the auth code. -// func landing(w http.ResponseWriter, r *http.Request) { -// http.Redirect(w, r, config.AuthCodeURL("foo"), http.StatusFound) -// } -// -// // The user will be redirected back to this handler, that takes the -// // "code" query parameter and Exchanges it for an access token. -// func handler(w http.ResponseWriter, r *http.Request) { -// t, err := config.NewTransportWithCode(r.FormValue("code")) -// // The Transport now has a valid Token. Create an *http.Client -// // with which we can make authenticated API requests. -// c := t.Client() -// c.Post(...) -// } -// package oauth2 import (