Skip to content

Commit

Permalink
Create and revoke OAuth tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
aggrolite committed May 5, 2015
1 parent 0b1dac4 commit d046ffa
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 0 deletions.
53 changes: 53 additions & 0 deletions oauth_request.go
@@ -0,0 +1,53 @@
package geddit

import (
"bytes"
"errors"
"io/ioutil"
"net/http"
"net/url"
)

type oauthRequest struct {
accessToken string
url string
useragent string
values *url.Values
}

func (r oauthRequest) getResponse() (*bytes.Buffer, error) {
// Determine the HTTP action.
var action, finalurl string
if r.values == nil {
action = "GET"
finalurl = r.url
} else {
action = "POST"
finalurl = r.url + "?" + r.values.Encode()
}

// Create a request and add the proper headers.
req, err := http.NewRequest(action, finalurl, nil)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", r.useragent)
req.Header.Set("Authorization", "bearer "+r.accessToken)

// Handle the request
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, errors.New(resp.Status)
}

respbytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}

return bytes.NewBuffer(respbytes), nil
}
133 changes: 133 additions & 0 deletions oauth_session.go
@@ -0,0 +1,133 @@
// Copyright 2012 Jimmy Zelinskie. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package reddit implements an abstraction for the reddit.com API.
package geddit

import (
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"net/url"
"strings"
)

// OAuthSession represents an OAuth session with reddit.com --
// all authenticated API calls are methods bound to this type.
type OAuthSession struct {
username string
password string
clientID string
clientSecret string
accessToken string
tokenType string
expiresIn int
scope string
useragent string
}

// NewLoginSession creates a new session for those who want to log into a
// reddit account via OAuth.
func NewOAuthSession(username, password, useragent, clientID, clientSecret string) (*OAuthSession, error) {
session := &OAuthSession{
username: username,
password: password,
clientID: clientID,
clientSecret: clientSecret,
useragent: useragent,
}

err := session.newToken(&url.Values{
"username": {username},
"password": {password},
"grant_type": {"password"},
})
if err != nil {
return nil, err
}
return session, nil
}

func (s *OAuthSession) newToken(postValues *url.Values) error {

loginURL := "https://www.reddit.com/api/v1/access_token"
req, err := http.NewRequest("POST", loginURL, strings.NewReader(postValues.Encode()))
if err != nil {
return err
}

req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

// Set the auth header
req.SetBasicAuth(s.clientID, s.clientSecret)

client := &http.Client{}

resp, err := client.Do(req)
defer resp.Body.Close()
if err != nil {
return err
}

if resp.StatusCode != http.StatusOK {
return errors.New(resp.Status)
}

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}

type Response struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
Scope string `json:"scope"`
}

r := &Response{}
err = json.Unmarshal(body, r)
if err != nil {
return err
}

s.accessToken = r.AccessToken
s.tokenType = r.TokenType
s.expiresIn = r.ExpiresIn
s.scope = r.Scope

return nil
}

func (s OAuthSession) RevokeToken() error {
revokeURL := "https://www.reddit.com/api/v1/revoke_token"
postValues := &url.Values{
"token": {s.accessToken},
"token_type_hint": {s.tokenType},
}
req, err := http.NewRequest("POST", revokeURL, strings.NewReader(postValues.Encode()))
if err != nil {
return err
}

req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.SetBasicAuth(s.clientID, s.clientSecret)

client := &http.Client{}

resp, err := client.Do(req)
defer resp.Body.Close()
if err != nil {
return err
}

// 401 returned if basic auth failed
// 204 is returned even if given token is invalid
if resp.StatusCode != http.StatusNoContent {
return errors.New(resp.Status)
}

return nil
}

0 comments on commit d046ffa

Please sign in to comment.