I'm using go's oauth2 package to make requests to Instagram on behalf of a user. The only part I have left to figure out is how to store the access/refresh token and then how do I use it again with oauth2? Here's the code I have so far, all it does is grab the access token and make one request to the API. After that I don't know what to do.
package main
import "net/http"
import "io/ioutil"
import "fmt"
import "html/template"
import "golang.org/x/oauth2"
var ClientID = YOUR_CLIENT_ID
var ClientSecret = YOUR_CLIENT_SECRET
var RedirectURI = "http://localhost:8080/redirect"
var authURL = "https://api.instagram.com/oauth/authorize"
var tokenURL = "https://api.instagram.com/oauth/access_token"
var templ = template.Must(template.New("index.html").ParseFiles("index.html"))
var igConf *oauth2.Config
func redirect(res http.ResponseWriter, req *http.Request) {
code := req.FormValue("code")
if len(code) != 0 {
tok, err := igConf.Exchange(oauth2.NoContext, code)
if err != nil {
fmt.Println(err)
http.NotFound(res, req)
return
}
if tok.Valid() {
client := igConf.Client(oauth2.NoContext, tok)
request, err := http.NewRequest("GET", "https://api.instagram.com/v1/users/self/?access_token="+tok.AccessToken, nil)
if err != nil {
fmt.Println(err)
http.NotFound(res, req)
return
}
resp, err := client.Do(request)
if err != nil {
fmt.Println(err)
http.NotFound(res, req)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
http.NotFound(res, req)
return
}
res.Write(body)
}
http.NotFound(res, req)
}
}
func homePage(res http.ResponseWriter, req *http.Request) {
url := igConf.AuthCodeURL("", oauth2.AccessTypeOffline)
fmt.Println(url)
err := templ.Execute(res, url)
if err != nil {
fmt.Println(err)
}
}
func main() {
igConf = &oauth2.Config{
ClientID: ClientID,
ClientSecret: ClientSecret,
Endpoint: oauth2.Endpoint{
AuthURL: authURL,
TokenURL: tokenURL,
},
RedirectURL: RedirectURI,
Scopes: []string{"public_content", "comments"},
}
http.HandleFunc("/redirect", redirect)
http.HandleFunc("/", homePage)
http.ListenAndServe(":8080", nil)
}
You could store the access token in a cookie, by inserting the following code immediately before the res.Write(body)
line in the redirect()
function:
res.SetCookie(&Cookie{
Name: "access_token",
Value: tok.AccessToken,
Expires: time.Now().Add(time.Hour * 24), // expires in 24 hours
}
In some other handler, you would read this token back again like this:
accessCookie, err := req.Cookie("access_token")
if err != nil {
res.WriteHeader(http.StatusUnauthorized)
fmt.Fprintln(res, "no access token provided")
return
}
accessToken := accessCookie.Value
// make your requests to Instagram here
Why would you store an Access Token?
Both Access and Refresh tokens are Bearer tokens and should be handled as defined in RFC 6750.
You are often better off simply re-doing the authorization flow when they come back and click the login button again.
If you store the token you need to worry about securing data in the token and these tokens give access to some fairly privileged information about your users.
I would suggest, where you can, move to OpenID Connect and where you are using JWT which are encrypted and signed.
-jim
hi i wrote a module to token storage and management with time delay for expiration time take a look to this module i think it can help you, i call this storage from my middleware to manage the tokens
# storage.go
package token_store
import (
"sync"
"time"
)
type item struct {
token string
lastAccess int64
}
// storage structure to managing the store tokens
type Storage struct {
storeMap map[string]*item
lock sync.Mutex
}
func NewStore(len, expireTime int64) (s *Storage) {
// initial the storage
s = &Store{storeMap: make(map[string]*item, len)}
go func() {
// each minute check that token has expired or not
for now := range time.Tick(time.Minute) {
// lock the cache for updating the values
s.lock.Lock()
for key, value := range s.storeMap {
/*
if expiration time exceeded then start to removing
the token from cache
*/
if now.Unix()-value.lastAccess > expireTime {
delete(s.storeMap, key)
}
}
s.lock.Unlock()
}
}()
return
}
func (s *Storage) Len() int {
// return the len of storage map
return len(s.storeMap)
}
func (s *Storage) Put(key, value string) {
/*
value will be the authentication token
key can be user-name or anay things that you
want to access token within it
*/
s.lock.Lock()
if it, ok := s.storeMap[key]; !ok { // if token is not exist
it = &item{value, time.Now().Unix()}
s.storeMap[key] = it
} else { // if token exist then update the last access time
it.lastAccess = time.Now().Unix()
}
s.lock.Unlock()
}
func (s *Storage) Get(key string) (value string) {
/*
check out hte item
*/
s.lock.Lock()
if item, ok := s.storeMap[key]; ok { // check if item exist then pass the value
value = item.token
item.lastAccess = time.Now().Unix()
}
s.lock.Unlock()
return
}
i hope this post be helpfull for you.