{"action":"created","comment":{"url":"https://api.github.com/repos/google/oauth2l/pulls/comments/76728001","id":76728001,"diff_hunk":"@@ -0,0 +1,316 @@\n+package oauth2client\n+\n+import (\n+\t\"crypto\"\n+\t\"crypto/ecdsa\"\n+\t\"crypto/rand\"\n+\t\"crypto/rsa\"\n+\t\"crypto/sha256\"\n+\t\"crypto/x509\"\n+\t\"encoding/base64\"\n+\t\"encoding/json\"\n+\t\"encoding/pem\"\n+\t\"fmt\"\n+\t\"io\"\n+\t\"io/ioutil\"\n+\t\"net/http\"\n+\t\"net/url\"\n+\t\"strconv\"\n+\t\"strings\"\n+\t\"time\"\n+)\n+\n+const (\n+\t// The URN for getting verification token offline\n+\toobCallbackUrn = \"urn:ietf:wg:oauth:2.0:oob\"\n+\t// The URN for token request grant type jwt-bearer\n+\tjwtBearerUrn = \"urn:ietf:params:oauth:grant-type:jwt-bearer\"\n+)\n+\n+// Signer interface to support both rsa and ecdsa sign.\n+type signerInterface interface {\n+\tsign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error)\n+}\n+\n+type rsaSigner struct {\n+\tpkey *rsa.PrivateKey\n+}\n+\n+func (s rsaSigner) sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {\n+\treturn s.pkey.Sign(rand, msg, opts)\n+}\n+\n+type ecdsaSigner struct {\n+\tpkey *ecdsa.PrivateKey\n+}\n+\n+func (s ecdsaSigner) sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {\n+\treturn s.pkey.Sign(rand, msg, opts)\n+}\n+\n+// handle 3LO authorize flow. prints the authorization URL on stdout and reads\n+// the verification code form stdin.\n+func defaultAuthorizeFlowHandler(authorizeUrl string) string {\n+\t// Print the url on console, let user authorize and paste the token back.\n+\tfmt.Printf(\"Go to the following link in your browser:\\n\\n   %s\\n\\n\", authorizeUrl)\n+\n+\tfmt.Println(\"Enter verification code: \")\n+\tcode := \"\"\n+\tfmt.Scanln(&code)\n+\treturn code\n+}\n+\n+// Run the three-legged oauth authorize flow.\n+func authorizeFlow(secret map[string]interface{}, scopes string, handler func(string) string) string {\n+\t// Marshaw a url to be printed on console. In web based oauth flow, the\n+\t// browser should redirect the user to this url\n+\tparamsMap := map[string]string{\n+\t\t\"access_type\":                 \"offline\",\n+\t\t\"auth_provider_x509_cert_url\": \"\",\n+\t\t\"redirect_uri\":                oobCallbackUrn,\n+\t\t\"response_type\":               \"code\",\n+\t\t\"client_id\":                   \"\",\n+\t\t\"scope\":                       scopes,\n+\t\t\"project_id\":                  \"\",\n+\t}\n+\n+\tparams := url.Values{}\n+\tfor key := range paramsMap {\n+\t\tif val, ok := secret[key]; ok {\n+\t\t\tparamsMap[key] = val.(string)\n+\t\t}\n+\t\tparams.Add(key, paramsMap[key])\n+\t}\n+\n+\t// Call the handler function to handle the authorize url. Return the verify\n+\t// code from handler.\n+\treturn handler(secret[\"auth_uri\"].(string) + \"?\" + params.Encode())\n+}\n+\n+// Run the three-legged oauth verification. Sends a request to auth_uri\n+// containing the verification code.\n+func verifyFlow(secret map[string]interface{}, scopes string, code string) (*Token, error) {\n+\t// Construct a POST request to fetch oauth token using the verificaton code.\n+\tpostData := map[string]string{\n+\t\t\"client_id\":    secret[\"client_id\"].(string),\n+\t\t\"code\":         code,\n+\t\t\"scope\":        scopes,\n+\t\t\"grant_type\":   \"authorization_code\",\n+\t\t\"redirect_uri\": oobCallbackUrn,\n+\t}\n+\tif clientSecret, ok := secret[\"client_secret\"]; ok {\n+\t\tpostData[\"client_secret\"] = clientSecret.(string)\n+\t}\n+\n+\tparams := url.Values{}\n+\tfor key := range postData {\n+\t\tparams.Add(key, postData[key])\n+\t}\n+\n+\t// Send the POST request.\n+\tresponse, err := http.PostForm(secret[\"token_uri\"].(string), params)\n+\tif err != nil {\n+\t\treturn nil, fmt.Errorf(\"Failed in http request to verify verification code.\")\n+\t}\n+\tdefer response.Body.Close()\n+\tbody, err := ioutil.ReadAll(response.Body)\n+\tif err != nil {\n+\t\treturn nil, fmt.Errorf(\"Failed to read http body for verification request.\")\n+\t}\n+\tvar token *Token\n+\tif err := json.Unmarshal(body, &token); err != nil {\n+\t\treturn nil, fmt.Errorf(\"Failed to parse json in verify flow.\")\n+\t}\n+\n+\treturn token, nil\n+}\n+\n+// Helper struct used in sign JWT\n+type sha256Opts struct{}\n+\n+func (r sha256Opts) HashFunc() crypto.Hash {\n+\treturn crypto.SHA256\n+}\n+\n+// Base 64 encode a block. The output doesn't contain the trailing double equal\n+// signs.\n+func base64Encode(b []byte) string {\n+\treturn strings.TrimSuffix(base64.URLEncoding.EncodeToString(b), \"==\")\n+}\n+\n+// Creates a signed JWT token. Used for two-legged oauth token request.\n+func createJWT(secret map[string]interface{}, scopes string, signer signerInterface) (string, error) {\n+\t// A valid JWT has an \"iat\" timestamp and an \"exp\" timestamp. Get the current\n+\t// time to create these timestamps.\n+\tnow := int(time.Now().Unix())\n+\n+\t// Construct the JWT header, which contains the private key id in the service\n+\t// account secret.\n+\theader := map[string]string{\n+\t\t\"typ\": \"JWT\",\n+\t\t\"alg\": \"RS256\",\n+\t\t\"kid\": secret[\"private_key_id\"].(string),\n+\t}\n+\n+\t// Construct the JWT payload.\n+\tpayload := map[string]string{\n+\t\t\"aud\":   secret[\"token_uri\"].(string),\n+\t\t\"scope\": scopes,\n+\t\t\"iat\":   strconv.Itoa(now),\n+\t\t\"exp\":   strconv.Itoa(now + 3600),\n+\t\t\"iss\":   secret[\"client_email\"].(string),\n+\t}\n+\n+\t// Convert the header and payload map to json.\n+\theaderJson, err := json.Marshal(header)\n+\tif err != nil {\n+\t\treturn \"\", fmt.Errorf(\"Failed to convert JWT header to json.\")\n+\t}\n+\tpayloadJson, err := json.Marshal(payload)\n+\tif err != nil {\n+\t\treturn \"\", fmt.Errorf(\"Failed to convert JWT payload to json.\")\n+\t}\n+\n+\t// Convert the header and payload json to base64\n+\theaderB64 := base64Encode(headerJson)\n+\tpayloadB64 := base64Encode(payloadJson)\n+\n+\t// The first two segments of the JWT are signed. The signature is the third\n+\t// segment.\n+\tsegments := headerB64 + \".\" + payloadB64\n+\n+\t// sign the hash, instead of the actual segments.\n+\thashed := sha256.Sum256([]byte(segments))\n+\tsignedBytes, err := signer.sign(rand.Reader, hashed[:], crypto.SignerOpts(sha256Opts{}))\n+\tif err != nil {\n+\t\treturn \"\", fmt.Errorf(\"Failed to sign JWT: %s\", err)\n+\t}\n+\n+\t// Generate the final JWT as\n+\t// base64(header) + \".\" + base64(payload) + \".\" + base64(signature)\n+\treturn segments + \".\" + base64Encode(signedBytes), nil\n+}\n+\n+// Struct for OAuth2 Client\n+type Client struct {\n+\t// The OAuth flow to run based on secret type.\n+\tflow func(scopes string) (*Token, error)\n+\n+\t// The function to handle two-legged oauth authorization flow. This function\n+\t// takes in a authorization URL. After the user authorizes on the given url,\n+\t// returns the verification code.\n+\tauthorizeHandler func(string) string\n+}\n+\n+// Create a new OAuth2 Client\n+// secretBytes: JSON text that represents either an OAuth client ID or a\n+// service account.\n+func NewClient(secretBytes []byte) (*Client, error) {\n+\tc := new(Client)\n+\tvar secret map[string]interface{}\n+\tif err := json.Unmarshal(secretBytes, &secret); err != nil {\n+\t\treturn nil, fmt.Errorf(\"Failed to parse secret json: %s\", err)\n+\t}\n+\n+\tif installed, found := secret[\"installed\"]; found {\n+\t\t// When the secret contains \"installed\" field, it is a client secret. We\n+\t\t// will run a three-legged flow\n+\t\tinstalledMap := installed.(map[string]interface{})\n+\t\tc.flow = func(scopes string) (*Token, error) {","path":"oauth2l-go/src/oauth2client/oauth2client.go","position":null,"original_position":219,"commit_id":"5bc569366d42bcd365d065e954467245ca50c8eb","original_commit_id":"eca83c7a5991069eba7253025815e5f7c47e9d15","user":{"login":"bochunz","id":3308339,"avatar_url":"https://avatars.githubusercontent.com/u/3308339?v=3","gravatar_id":"","url":"https://api.github.com/users/bochunz","html_url":"https://github.com/bochunz","followers_url":"https://api.github.com/users/bochunz/followers","following_url":"https://api.github.com/users/bochunz/following{/other_user}","gists_url":"https://api.github.com/users/bochunz/gists{/gist_id}","starred_url":"https://api.github.com/users/bochunz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bochunz/subscriptions","organizations_url":"https://api.github.com/users/bochunz/orgs","repos_url":"https://api.github.com/users/bochunz/repos","events_url":"https://api.github.com/users/bochunz/events{/privacy}","received_events_url":"https://api.github.com/users/bochunz/received_events","type":"User","site_admin":false},"body":"Done","created_at":"2016-08-30T04:12:10Z","updated_at":"2016-08-30T04:12:10Z","html_url":"https://github.com/google/oauth2l/pull/21#discussion_r76728001","pull_request_url":"https://api.github.com/repos/google/oauth2l/pulls/21","_links":{"self":{"href":"https://api.github.com/repos/google/oauth2l/pulls/comments/76728001"},"html":{"href":"https://github.com/google/oauth2l/pull/21#discussion_r76728001"},"pull_request":{"href":"https://api.github.com/repos/google/oauth2l/pulls/21"}}},"pull_request":{"url":"https://api.github.com/repos/google/oauth2l/pulls/21","id":82969842,"html_url":"https://github.com/google/oauth2l/pull/21","diff_url":"https://github.com/google/oauth2l/pull/21.diff","patch_url":"https://github.com/google/oauth2l/pull/21.patch","issue_url":"https://api.github.com/repos/google/oauth2l/issues/21","number":21,"state":"open","locked":false,"title":"Add oauth2-go","user":{"login":"bochunz","id":3308339,"avatar_url":"https://avatars.githubusercontent.com/u/3308339?v=3","gravatar_id":"","url":"https://api.github.com/users/bochunz","html_url":"https://github.com/bochunz","followers_url":"https://api.github.com/users/bochunz/followers","following_url":"https://api.github.com/users/bochunz/following{/other_user}","gists_url":"https://api.github.com/users/bochunz/gists{/gist_id}","starred_url":"https://api.github.com/users/bochunz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bochunz/subscriptions","organizations_url":"https://api.github.com/users/bochunz/orgs","repos_url":"https://api.github.com/users/bochunz/repos","events_url":"https://api.github.com/users/bochunz/events{/privacy}","received_events_url":"https://api.github.com/users/bochunz/received_events","type":"User","site_admin":false},"body":"Tests pending\r\n\r\nTo try it:\r\nexport GOPATH=[path/to]/oauth2l/oauth2l-go\r\ngo run [path/to]/oauth2l-go/src/oauth2l/oauth2l.go --json <secret.json> fetch cloud-platform","created_at":"2016-08-26T23:59:10Z","updated_at":"2016-08-30T04:12:10Z","closed_at":null,"merged_at":null,"merge_commit_sha":"89f175ca0ee923717d051673cf81a099ddd34fc0","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/google/oauth2l/pulls/21/commits","review_comments_url":"https://api.github.com/repos/google/oauth2l/pulls/21/comments","review_comment_url":"https://api.github.com/repos/google/oauth2l/pulls/comments{/number}","comments_url":"https://api.github.com/repos/google/oauth2l/issues/21/comments","statuses_url":"https://api.github.com/repos/google/oauth2l/statuses/5bc569366d42bcd365d065e954467245ca50c8eb","head":{"label":"bochunz:go","ref":"go","sha":"5bc569366d42bcd365d065e954467245ca50c8eb","user":{"login":"bochunz","id":3308339,"avatar_url":"https://avatars.githubusercontent.com/u/3308339?v=3","gravatar_id":"","url":"https://api.github.com/users/bochunz","html_url":"https://github.com/bochunz","followers_url":"https://api.github.com/users/bochunz/followers","following_url":"https://api.github.com/users/bochunz/following{/other_user}","gists_url":"https://api.github.com/users/bochunz/gists{/gist_id}","starred_url":"https://api.github.com/users/bochunz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bochunz/subscriptions","organizations_url":"https://api.github.com/users/bochunz/orgs","repos_url":"https://api.github.com/users/bochunz/repos","events_url":"https://api.github.com/users/bochunz/events{/privacy}","received_events_url":"https://api.github.com/users/bochunz/received_events","type":"User","site_admin":false},"repo":{"id":64711142,"name":"oauth2l","full_name":"bochunz/oauth2l","owner":{"login":"bochunz","id":3308339,"avatar_url":"https://avatars.githubusercontent.com/u/3308339?v=3","gravatar_id":"","url":"https://api.github.com/users/bochunz","html_url":"https://github.com/bochunz","followers_url":"https://api.github.com/users/bochunz/followers","following_url":"https://api.github.com/users/bochunz/following{/other_user}","gists_url":"https://api.github.com/users/bochunz/gists{/gist_id}","starred_url":"https://api.github.com/users/bochunz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bochunz/subscriptions","organizations_url":"https://api.github.com/users/bochunz/orgs","repos_url":"https://api.github.com/users/bochunz/repos","events_url":"https://api.github.com/users/bochunz/events{/privacy}","received_events_url":"https://api.github.com/users/bochunz/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/bochunz/oauth2l","description":"oauth2l (\"oauth tool\") is a simple CLI for interacting with Google oauth tokens.","fork":true,"url":"https://api.github.com/repos/bochunz/oauth2l","forks_url":"https://api.github.com/repos/bochunz/oauth2l/forks","keys_url":"https://api.github.com/repos/bochunz/oauth2l/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bochunz/oauth2l/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bochunz/oauth2l/teams","hooks_url":"https://api.github.com/repos/bochunz/oauth2l/hooks","issue_events_url":"https://api.github.com/repos/bochunz/oauth2l/issues/events{/number}","events_url":"https://api.github.com/repos/bochunz/oauth2l/events","assignees_url":"https://api.github.com/repos/bochunz/oauth2l/assignees{/user}","branches_url":"https://api.github.com/repos/bochunz/oauth2l/branches{/branch}","tags_url":"https://api.github.com/repos/bochunz/oauth2l/tags","blobs_url":"https://api.github.com/repos/bochunz/oauth2l/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bochunz/oauth2l/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bochunz/oauth2l/git/refs{/sha}","trees_url":"https://api.github.com/repos/bochunz/oauth2l/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bochunz/oauth2l/statuses/{sha}","languages_url":"https://api.github.com/repos/bochunz/oauth2l/languages","stargazers_url":"https://api.github.com/repos/bochunz/oauth2l/stargazers","contributors_url":"https://api.github.com/repos/bochunz/oauth2l/contributors","subscribers_url":"https://api.github.com/repos/bochunz/oauth2l/subscribers","subscription_url":"https://api.github.com/repos/bochunz/oauth2l/subscription","commits_url":"https://api.github.com/repos/bochunz/oauth2l/commits{/sha}","git_commits_url":"https://api.github.com/repos/bochunz/oauth2l/git/commits{/sha}","comments_url":"https://api.github.com/repos/bochunz/oauth2l/comments{/number}","issue_comment_url":"https://api.github.com/repos/bochunz/oauth2l/issues/comments{/number}","contents_url":"https://api.github.com/repos/bochunz/oauth2l/contents/{+path}","compare_url":"https://api.github.com/repos/bochunz/oauth2l/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bochunz/oauth2l/merges","archive_url":"https://api.github.com/repos/bochunz/oauth2l/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bochunz/oauth2l/downloads","issues_url":"https://api.github.com/repos/bochunz/oauth2l/issues{/number}","pulls_url":"https://api.github.com/repos/bochunz/oauth2l/pulls{/number}","milestones_url":"https://api.github.com/repos/bochunz/oauth2l/milestones{/number}","notifications_url":"https://api.github.com/repos/bochunz/oauth2l/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bochunz/oauth2l/labels{/name}","releases_url":"https://api.github.com/repos/bochunz/oauth2l/releases{/id}","deployments_url":"https://api.github.com/repos/bochunz/oauth2l/deployments","created_at":"2016-08-02T00:36:40Z","updated_at":"2016-08-02T00:36:41Z","pushed_at":"2016-08-30T04:10:19Z","git_url":"git://github.com/bochunz/oauth2l.git","ssh_url":"git@github.com:bochunz/oauth2l.git","clone_url":"https://github.com/bochunz/oauth2l.git","svn_url":"https://github.com/bochunz/oauth2l","homepage":"","size":57,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":false,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"google:master","ref":"master","sha":"8c932157f36c6d6ead4a2ed4b3ee031d89f0427d","user":{"login":"google","id":1342004,"avatar_url":"https://avatars.githubusercontent.com/u/1342004?v=3","gravatar_id":"","url":"https://api.github.com/users/google","html_url":"https://github.com/google","followers_url":"https://api.github.com/users/google/followers","following_url":"https://api.github.com/users/google/following{/other_user}","gists_url":"https://api.github.com/users/google/gists{/gist_id}","starred_url":"https://api.github.com/users/google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/google/subscriptions","organizations_url":"https://api.github.com/users/google/orgs","repos_url":"https://api.github.com/users/google/repos","events_url":"https://api.github.com/users/google/events{/privacy}","received_events_url":"https://api.github.com/users/google/received_events","type":"Organization","site_admin":false},"repo":{"id":55125415,"name":"oauth2l","full_name":"google/oauth2l","owner":{"login":"google","id":1342004,"avatar_url":"https://avatars.githubusercontent.com/u/1342004?v=3","gravatar_id":"","url":"https://api.github.com/users/google","html_url":"https://github.com/google","followers_url":"https://api.github.com/users/google/followers","following_url":"https://api.github.com/users/google/following{/other_user}","gists_url":"https://api.github.com/users/google/gists{/gist_id}","starred_url":"https://api.github.com/users/google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/google/subscriptions","organizations_url":"https://api.github.com/users/google/orgs","repos_url":"https://api.github.com/users/google/repos","events_url":"https://api.github.com/users/google/events{/privacy}","received_events_url":"https://api.github.com/users/google/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/google/oauth2l","description":"oauth2l (\"oauth tool\") is a simple CLI for interacting with Google oauth tokens.","fork":false,"url":"https://api.github.com/repos/google/oauth2l","forks_url":"https://api.github.com/repos/google/oauth2l/forks","keys_url":"https://api.github.com/repos/google/oauth2l/keys{/key_id}","collaborators_url":"https://api.github.com/repos/google/oauth2l/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/google/oauth2l/teams","hooks_url":"https://api.github.com/repos/google/oauth2l/hooks","issue_events_url":"https://api.github.com/repos/google/oauth2l/issues/events{/number}","events_url":"https://api.github.com/repos/google/oauth2l/events","assignees_url":"https://api.github.com/repos/google/oauth2l/assignees{/user}","branches_url":"https://api.github.com/repos/google/oauth2l/branches{/branch}","tags_url":"https://api.github.com/repos/google/oauth2l/tags","blobs_url":"https://api.github.com/repos/google/oauth2l/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/google/oauth2l/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/google/oauth2l/git/refs{/sha}","trees_url":"https://api.github.com/repos/google/oauth2l/git/trees{/sha}","statuses_url":"https://api.github.com/repos/google/oauth2l/statuses/{sha}","languages_url":"https://api.github.com/repos/google/oauth2l/languages","stargazers_url":"https://api.github.com/repos/google/oauth2l/stargazers","contributors_url":"https://api.github.com/repos/google/oauth2l/contributors","subscribers_url":"https://api.github.com/repos/google/oauth2l/subscribers","subscription_url":"https://api.github.com/repos/google/oauth2l/subscription","commits_url":"https://api.github.com/repos/google/oauth2l/commits{/sha}","git_commits_url":"https://api.github.com/repos/google/oauth2l/git/commits{/sha}","comments_url":"https://api.github.com/repos/google/oauth2l/comments{/number}","issue_comment_url":"https://api.github.com/repos/google/oauth2l/issues/comments{/number}","contents_url":"https://api.github.com/repos/google/oauth2l/contents/{+path}","compare_url":"https://api.github.com/repos/google/oauth2l/compare/{base}...{head}","merges_url":"https://api.github.com/repos/google/oauth2l/merges","archive_url":"https://api.github.com/repos/google/oauth2l/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/google/oauth2l/downloads","issues_url":"https://api.github.com/repos/google/oauth2l/issues{/number}","pulls_url":"https://api.github.com/repos/google/oauth2l/pulls{/number}","milestones_url":"https://api.github.com/repos/google/oauth2l/milestones{/number}","notifications_url":"https://api.github.com/repos/google/oauth2l/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/google/oauth2l/labels{/name}","releases_url":"https://api.github.com/repos/google/oauth2l/releases{/id}","deployments_url":"https://api.github.com/repos/google/oauth2l/deployments","created_at":"2016-03-31T06:18:20Z","updated_at":"2016-08-21T19:54:05Z","pushed_at":"2016-08-30T04:10:20Z","git_url":"git://github.com/google/oauth2l.git","ssh_url":"git@github.com:google/oauth2l.git","clone_url":"https://github.com/google/oauth2l.git","svn_url":"https://github.com/google/oauth2l","homepage":"","size":59,"stargazers_count":10,"watchers_count":10,"language":"Python","has_issues":true,"has_downloads":false,"has_wiki":true,"has_pages":false,"forks_count":6,"mirror_url":null,"open_issues_count":2,"forks":6,"open_issues":2,"watchers":10,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/google/oauth2l/pulls/21"},"html":{"href":"https://github.com/google/oauth2l/pull/21"},"issue":{"href":"https://api.github.com/repos/google/oauth2l/issues/21"},"comments":{"href":"https://api.github.com/repos/google/oauth2l/issues/21/comments"},"review_comments":{"href":"https://api.github.com/repos/google/oauth2l/pulls/21/comments"},"review_comment":{"href":"https://api.github.com/repos/google/oauth2l/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/google/oauth2l/pulls/21/commits"},"statuses":{"href":"https://api.github.com/repos/google/oauth2l/statuses/5bc569366d42bcd365d065e954467245ca50c8eb"}}}}
{"actor":{"display_login":"bochunz"}}