I am not able to retrieve the access token using the following go code - go

func handler(w http.ResponseWriter, r *http.Request) {
t := &oauth.Transport{Config: config}
c := r.FormValue("code")
token, err := t.Exchange(c)
fmt.Println("token: ", token, "\nerr: ", err)
}
Error:
token: <nil>
err: OAuthError: updateToken: Unexpected HTTP status 400 Bad Request

Do you use goauth2 package, which is deprecated? If so you can try golang.org/x/oauth2 instead
package main
import (
"log"
"net/http"
"code.google.com/p/google-api-go-client/youtube/v3"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
)
// variables used during oauth protocol flow of authentication
var (
code = ""
token = ""
)
var oauthCfg = &oauth2.Config{
ClientID: "...",
ClientSecret: "...",
RedirectURL: "http://localhost:8888/oauth2callback",
Scopes: []string{
youtube.YoutubeScope, //e.g.
},
Endpoint: google.Endpoint,
}
func main() {
http.HandleFunc("/", mainHander)
http.HandleFunc("/oauth2callback", callbackHandler)
http.ListenAndServe(":8888", nil)
}
func mainHander(w http.ResponseWriter, r *http.Request) {
url := oauthCfg.AuthCodeURL("")
http.Redirect(w, r, url, http.StatusFound)
}
func callbackHandler(w http.ResponseWriter, r *http.Request) {
code := r.FormValue("code")
tok, err := oauthCfg.Exchange(oauth2.NoContext, code)
if err != nil {
log.Fatal(err)
}
log.Println(tok)
}

Related

Golang ServeHTTP make proxy error EOF on POST request

I’m working on proxy server with gin and ServeHTTP. 
Actually GET and OPTIONS request works well. But when I trying multiples POST request I get EOF error one in two request.
I’ve test to make repeat request without proxy service and its work well, so there is something not working in my code.
Edit :
I have test POST proxy with https://ptsv2.com/ and all request response return 200 status code.
// main.go
package main
import (
"fmt"
"../pkg/api"
)
func main() {
fmt.Println("Starting server")
api.InitServer()
}
// routes.go
package api
import (
"github.com/gin-gonic/gin"
)
const serviceUrl = "http://localhost:8732"
func InitServer() {
router := gin.Default()
defineRoutes(router)
router.Run()
}
func defineRoutes(router *gin.Engine) {
router.GET("/ping", Ping)
router.POST("/*any", Proxy(serviceUrl))
}
// controller.go
package api
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"net/http/httputil"
"net/url"
"strconv"
"github.com/gin-gonic/gin"
)
type transport struct {
http.RoundTripper
}
func (t *transport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
resp, err = t.RoundTripper.RoundTrip(req)
if err != nil {
// EOF ERROR HERE
return nil, err
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
err = resp.Body.Close()
if err != nil {
return nil, err
}
b = bytes.Replace(b, []byte("server"), []byte("schmerver"), -1)
body := ioutil.NopCloser(bytes.NewReader(b))
response := resp
response.Body = body
response.ContentLength = int64(len(b))
response.Header.Set("Content-Length", strconv.Itoa(len(b)))
response.Header.Set("Access-Control-Allow-Origin", "*")
return response, nil
}
func Proxy(targetUrl string) gin.HandlerFunc {
fn := func(c *gin.Context) {
remote, err := url.Parse(targetUrl)
if err != nil {
panic(err)
}
proxy := httputil.NewSingleHostReverseProxy(remote)
proxy.Director = func(req *http.Request) {
req.Header = c.Request.Header
req.Host = remote.Host
req.URL.Scheme = remote.Scheme
req.URL.Host = remote.Host
req.Close = true // True / False same result
}
proxy.Transport = &transport{http.DefaultTransport}
proxy.ServeHTTP(c.Writer, c.Request)
}
return fn
}
conclusion
your code have no bug. it works. maybe your network setting is wrong.
explain
I download your code and test it with a local backend server. It works.
appendix
backend server code
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
fmt.Println("Starting server")
router := gin.Default()
router.POST("/*any", func(c *gin.Context) {
c.JSON(200, gin.H{
"mes": "hello",
})
})
router.Run(":8888")
}

How can I integrate javascript hot reload into golang routing with https for development?

I would like to set up the next simple development setup for golang + svelte
Frontend part
$ npx degit sveltejs/template frontend
$ yarn
$ yarn dev # it start the frontend env on http://localhost:5000
So I have a running frontend on http://localhost:5000
Backend part
go net/http router with https on :443 with self signed cert created with mkcert
https://localhost/hello -> go handlers for show normal go handlers
https://localhost/ -> reverse proxied http://localhost:5000
package main
import (
"bytes"
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
"net/url"
"strconv"
)
func newDirector(origin url.URL) func(*http.Request) {
return func(req *http.Request) {
req.Header.Add("X-Forwarded-Host", req.Host)
req.Header.Add("X-Origin-Host", origin.Host)
req.URL.Scheme = "http"
req.URL.Host = origin.Host
}
}
func newReplacer(orig, replace string) func(resp *http.Response) error {
return func(resp *http.Response) error {
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
err = resp.Body.Close()
if err != nil {
return err
}
b = bytes.Replace(b, []byte(orig), []byte(replace), -1)
body := ioutil.NopCloser(bytes.NewReader(b))
resp.Body = body
resp.ContentLength = int64(len(b))
resp.Header.Set("Content-Length", strconv.Itoa(len(b)))
return nil
}
}
func Frontend(w http.ResponseWriter, r *http.Request) {
origin, _ := url.Parse("http://localhost:5000/")
director := newDirector(*origin)
proxy := &httputil.ReverseProxy{Director: director}
proxy.ServeHTTP(w, r)
}
func liverload_js(w http.ResponseWriter, r *http.Request) {
origin, _ := url.Parse("http://localhost:35729/")
director := newDirector(*origin)
modifier := newReplacer("this.port = 35729;", "this.port = 443;")
proxy := &httputil.ReverseProxy{Director: director, ModifyResponse: modifier}
proxy.ServeHTTP(w, r)
}
func liverload_ws(w http.ResponseWriter, r *http.Request) {
origin, _ := url.Parse("http://localhost:35729/")
director := newDirector(*origin)
proxy := &httputil.ReverseProxy{Director: director}
proxy.ServeHTTP(w, r)
}
func Bundle_js(w http.ResponseWriter, r *http.Request) {
origin, _ := url.Parse("http://localhost:5000/")
director := newDirector(*origin)
modifier := newReplacer(":35729/livereload.js?snipver=1", ":443/livereload.js?snipver=1")
proxy := &httputil.ReverseProxy{Director: director, ModifyResponse: modifier}
proxy.ServeHTTP(w, r)
}
func main() {
http.HandleFunc("/build/bundle.js", Bundle_js)
http.HandleFunc("/livereload.js", liverload_js)
http.HandleFunc("/livereload", liverload_ws)
http.HandleFunc("/", Frontend)
log.Fatal(http.ListenAndServeTLS(":443", "cert.pem", "key.pem", nil))
}
It is reload with pushing the F5 but the hot reload not goes trough the ws proxy.
How can it be included into the proxy ?
If you install Caddy then you can use this as your Caddyfile:
http://localhost {
redir https://{host}{uri}
}
https://localhost {
tls /path/to/cert.crt /path/to/cert.key
proxy /API localhost:5000 {
without /API
}
proxy / localhost:5000
}
Freelancer helped me to find the answer.
The trick was that I used Scheme="http" in each proxied request even httputil.ReverseProxy support websocket natively.
func newDirector(origin url.URL) func(*http.Request) {
return func(req *http.Request) {
req.Header.Add("X-Forwarded-Host", req.Host)
req.Header.Add("X-Origin-Host", origin.Host)
req.URL.Scheme = "http"
req.URL.Host = origin.Host
}
}
should be
func newDirector(origin url.URL) func(*http.Request) {
return func(req *http.Request) {
req.Header.Add("X-Forwarded-Host", req.Host)
req.Header.Add("X-Origin-Host", origin.Host)
req.URL.Scheme = origin.Scheme
req.URL.Host = origin.Host
}
}
The complete code became
package main
import (
"bytes"
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
"net/url"
"strconv"
)
func newDirector(origin url.URL) func(*http.Request) {
return func(req *http.Request) {
req.Header.Add("X-Forwarded-Host", req.Host)
req.Header.Add("X-Origin-Host", origin.Host)
req.URL.Scheme = origin.Scheme
req.URL.Host = origin.Host
}
}
func newReplacer(orig, replace string) func(resp *http.Response) error {
return func(resp *http.Response) error {
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
err = resp.Body.Close()
if err != nil {
return err
}
b = bytes.Replace(b, []byte(orig), []byte(replace), -1)
body := ioutil.NopCloser(bytes.NewReader(b))
resp.Body = body
resp.ContentLength = int64(len(b))
resp.Header.Set("Content-Length", strconv.Itoa(len(b)))
return nil
}
}
func Frontend(w http.ResponseWriter, r *http.Request) {
origin, _ := url.Parse("http://localhost:5000/")
director := newDirector(*origin)
proxy := &httputil.ReverseProxy{Director: director}
proxy.ServeHTTP(w, r)
}
func liverload_js(w http.ResponseWriter, r *http.Request) {
origin, _ := url.Parse("http://localhost:35729/")
director := newDirector(*origin)
modifier := newReplacer("this.port = 35729;", "this.port = 443;")
proxy := &httputil.ReverseProxy{Director: director, ModifyResponse: modifier}
proxy.ServeHTTP(w, r)
}
func liverload_ws(w http.ResponseWriter, r *http.Request) {
origin, _ := url.Parse("http://localhost:35729/")
director := newDirector(*origin)
proxy := &httputil.ReverseProxy{Director: director}
proxy.ServeHTTP(w, r)
}
func Bundle_js(w http.ResponseWriter, r *http.Request) {
origin, _ := url.Parse("http://localhost:5000/")
director := newDirector(*origin)
modifier := newReplacer(":35729/livereload.js?snipver=1", ":443/livereload.js?snipver=1")
proxy := &httputil.ReverseProxy{Director: director, ModifyResponse: modifier}
proxy.ServeHTTP(w, r)
}
func main() {
http.HandleFunc("/build/bundle.js", Bundle_js)
http.HandleFunc("/livereload.js", liverload_js)
http.HandleFunc("/livereload", liverload_ws)
http.HandleFunc("/", Frontend)
log.Fatal(http.ListenAndServeTLS(":443", "cert.pem", "key.pem", nil))
}

How can I use data received as response from google api?

I'm trying to create login with google api authentication with oauth2.
I'm getting response from google api (response.body) as:
{
"id": "received ID",
"email": "EMAIL",
"verified_email": true,
"name": "Name",
}
How can I access that data inside go program so that I can store it in database?
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"strings"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"encoding/json"
)
var (
oauthConf = &oauth2.Config{
ClientID: "CLIENTID",
ClientSecret: "Secret",
RedirectURL: "http://localhost:8011/showprofile",
//Scopes: []string{"https://www.googleapis.com/auth/plus.login"},
Scopes:[]string{"profile","email"},
Endpoint: google.Endpoint,
}
oauthStateString = "thisshouldberandom"
)
const htmlIndex = `<html><body>
Logged in with facebook
</body></html>
`
func handleMain(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK)
w.Write([]byte(htmlIndex))
}
func handleGoogleLogin(w http.ResponseWriter, r *http.Request) {
Url, err := url.Parse(oauthConf.Endpoint.AuthURL)
if err != nil {
log.Fatal("Parse: ", err)
}
parameters := url.Values{}
parameters.Add("client_id", oauthConf.ClientID)
parameters.Add("scope", strings.Join(oauthConf.Scopes, " "))
parameters.Add("redirect_uri", oauthConf.RedirectURL)
parameters.Add("response_type", "code")
parameters.Add("state", oauthStateString)
Url.RawQuery = parameters.Encode()
url := Url.String()
fmt.Println("URL" + url)
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
}
func handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
fmt.Println("Call back working")
state := r.FormValue("state")
if state != oauthStateString {
fmt.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthStateString, state)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
code := r.FormValue("code")
token, err := oauthConf.Exchange(oauth2.NoContext, code)
if err != nil {
fmt.Printf("oauthConf.Exchange() failed with '%s'\n", err)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
resp,err:= http.Get("https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + token.AccessToken)
if err != nil {
fmt.Printf("Get: %s\n", err)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
fmt.Println(resp.Body)
defer resp.Body.Close()
response, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("ReadAll: %s\n", err)
http.Redirect(w, r, "/showprofile", http.StatusTemporaryRedirect)
return
}
log.Printf("parseResponseBody: %s\n", string(response))
http.Redirect(w, r, "/showprofile", http.StatusTemporaryRedirect)
}
func main() {
http.HandleFunc("/", handleMain)
http.HandleFunc("/login", handleGoogleLogin)
http.HandleFunc("/showprofile", handleGoogleCallback)
fmt.Print("Started running on http://localhost:8011\n")
log.Fatal(http.ListenAndServe(":8011", nil))
}
Fixed it by using json.Unmarshal.

Unable to protect gorilla/mux Subroute with basic auth

I am trying to create routes using gorilla/mux, some of which should be protected by basic auth and others shouldn't. Specifically, every route under /v2 should require basic auth, but the routes under /health should be publicly accessible.
As you can see below, I can wrap each of my /v2 route handlers with BasicAuth(), but that's against the DRY principle, and also error prone, not to mention the security implications of forgetting to wrap one of those handlers.
I have the following output from curl. All but the last one is as I expect. One should not be able to GET /smallcat without authentication.
$ curl localhost:3000/health/ping
"PONG"
$ curl localhost:3000/health/ping/
404 page not found
$ curl localhost:3000/v2/bigcat
Unauthorised.
$ curl apiuser:apipass#localhost:3000/v2/bigcat
"Big MEOW"
$ curl localhost:3000/v2/smallcat
"Small Meow"
Here's the complete code. I believe I need to fix the v2Router definition somehow, but fail to see how.
package main
import (
"crypto/subtle"
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
)
func endAPICall(w http.ResponseWriter, httpStatus int, anyStruct interface{}) {
result, err := json.MarshalIndent(anyStruct, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(httpStatus)
w.Write(result)
}
func BasicAuth(handler http.HandlerFunc, username, password, realm string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user, pass, ok := r.BasicAuth()
if !ok || subtle.ConstantTimeCompare([]byte(user), []byte(username)) != 1 || subtle.ConstantTimeCompare([]byte(pass), []byte(password)) != 1 {
w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
w.WriteHeader(401)
w.Write([]byte("Unauthorised.\n"))
return
}
handler(w, r)
}
}
func routers() *mux.Router {
username := "apiuser"
password := "apipass"
noopHandler := func(http.ResponseWriter, *http.Request) {}
topRouter := mux.NewRouter().StrictSlash(false)
healthRouter := topRouter.PathPrefix("/health/").Subrouter()
v2Router := topRouter.PathPrefix("/v2").HandlerFunc(BasicAuth(noopHandler, username, password, "Provide username and password")).Subrouter()
healthRouter.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
endAPICall(w, 200, "PONG")
})
v2Router.HandleFunc("/smallcat", func(w http.ResponseWriter, r *http.Request) {
endAPICall(w, 200, "Small Meow")
})
bigMeowFn := func(w http.ResponseWriter, r *http.Request) {
endAPICall(w, 200, "Big MEOW")
}
v2Router.HandleFunc("/bigcat", BasicAuth(bigMeowFn, username, password, "Provide username and password"))
return topRouter
}
func main() {
if r := routers(); r != nil {
log.Fatal("Server exited:", http.ListenAndServe(":3000", r))
}
}
I achieved the expected behavior by using negroni. If the BasicAuth() call fails, none of the route handlers under /v2 are invoked.
The working code is in a Gist (with revisions, for those interested) here: https://gist.github.com/gurjeet/13b2f69af6ac80c0357ab20ee24fa575
Per SO convention, though, here's the complete code:
package main
import (
"crypto/subtle"
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/urfave/negroni"
)
func endAPICall(w http.ResponseWriter, httpStatus int, anyStruct interface{}) {
result, err := json.MarshalIndent(anyStruct, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(httpStatus)
w.Write(result)
}
func BasicAuth(w http.ResponseWriter, r *http.Request, username, password, realm string) bool {
user, pass, ok := r.BasicAuth()
if !ok || subtle.ConstantTimeCompare([]byte(user), []byte(username)) != 1 || subtle.ConstantTimeCompare([]byte(pass), []byte(password)) != 1 {
w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
w.WriteHeader(401)
w.Write([]byte("Unauthorised.\n"))
return false
}
return true
}
func routers() *mux.Router {
username := "apiuser"
password := "apipass"
v2Path := "/v2"
healthPath := "/health"
topRouter := mux.NewRouter().StrictSlash(true)
healthRouter := mux.NewRouter().PathPrefix(healthPath).Subrouter().StrictSlash(true)
v2Router := mux.NewRouter().PathPrefix(v2Path).Subrouter().StrictSlash(true)
healthRouter.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
endAPICall(w, 200, "PONG")
})
v2Router.HandleFunc("/smallcat", func(w http.ResponseWriter, r *http.Request) {
endAPICall(w, 200, "Small Meow")
})
bigMeowFn := func(w http.ResponseWriter, r *http.Request) {
endAPICall(w, 200, "Big MEOW")
}
v2Router.HandleFunc("/bigcat", bigMeowFn)
topRouter.PathPrefix(healthPath).Handler(negroni.New(
/* Health-check routes are unprotected */
negroni.Wrap(healthRouter),
))
topRouter.PathPrefix(v2Path).Handler(negroni.New(
negroni.HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
if BasicAuth(w, r, username, password, "Provide user name and password") {
/* Call the next handler iff Basic-Auth succeeded */
next(w, r)
}
}),
negroni.Wrap(v2Router),
))
return topRouter
}
func main() {
if r := routers(); r != nil {
log.Fatal("Server exited:", http.ListenAndServe(":3000", r))
}
}

social network vk auth with martini

I am trying to use vk auth with martini. But have error on compile:
/goPath/vkAuthTry2.go:38: undefined: YourRedirectFunc
The question is how to define YourRedirectFunc function. Or if ask more widely I need working example of martini app with vk social network authentication or if even more widely an example of any golang website using vk authentication.
Full code:
package main
import (
"github.com/go-martini/martini"
"github.com/yanple/vk_api"
"net/http"
)
var api vk_api.Api
func prepareMartini() *martini.ClassicMartini {
m := martini.Classic()
m.Get("/somePage", func(w http.ResponseWriter, r *http.Request) {
// And receive token on the special method (redirect uri)
currentUrl := r.URL.RequestURI() // for example "yoursite.com/get_access_token#access_token=3304fdb7c3b69ace6b055c6cba34e5e2f0229f7ac2ee4ef46dc9f0b241143bac993e6ced9a3fbc111111&expires_in=0&user_id=1"
accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(currentUrl)
if err != nil {
panic(err)
}
api.AccessToken = accessToken
api.UserId = userId
api.ExpiresIn = expiresIn
w.Write([]byte("somePage"))
})
return m
}
func main() {
authUrl, err := api.GetAuthUrl(
"domain.com/method_get_access_token", // redirect URI
"token", // response type
"4672050", // client id
"wall,offline", // permissions https://vk.com/dev/permissions
)
if err != nil {
panic(err)
}
YourRedirectFunc(authUrl)
prepareMartini().Run()
}
Update
I edited my code according to #Elwinar's answer:
package main
import (
"fmt"
"github.com/go-martini/martini"
"github.com/yanple/vk_api"
"net/http"
)
var api vk_api.Api
func prepareMartini() *martini.ClassicMartini {
m := martini.Classic()
// This handler redirect the request to the vkontact system, which
// will perform the authentification then redirect the request to
// the URL we gave as the first paraemeter of the GetAuthUrl method
// (treated by the second handler)
m.Get("/vk/auth", func(w http.ResponseWriter, r *http.Request) {
var api vk_api.Api
authUrl, err := api.GetAuthUrl("http://localhost:3000/vk/token", "token", "4672050", "wall,offline")
if err != nil {
panic(err)
}
http.Redirect(w, r, authUrl, http.StatusFound)
})
// This handler is the one that get the actual authentification
// information from the vkontact api. You get the access token,
// userid and expiration date of the authentification session.
// You can do whatever you want with them, generally storing them
// in session to be able to get the actual informations later using
// the access token.
m.Get("/vk/token", func(w http.ResponseWriter, r *http.Request) {
accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(r.URL.String())
if err != nil {
panic(err)
}
fmt.Println(accessToken)
fmt.Println(userId)
fmt.Println(expiresIn)
})
return m
}
func main() {
prepareMartini().Run()
}
now no complie errors, but still cannot login.
When I opened http://localhost:3000/vk/auth I was redirected on page...
https://oauth.vk.com/authorize?client_id=MY_APP_ID&redirect_uri=localhost%3A3000%2Fvk%2Ftoken&response_type=token&scope=wall%2Coffline
... and got the following browser output:
{"error":"invalid_request","error_description":"redirect_uri is incorrect, check application domain in the settings page"}
Of course instead of 4672050 I pasted my app id. This app was specially generated for localhost:3000.
Maybe I need to paste somewhere my private key for oauth like pYFR2Xojlkad87880dLa.
Update 2
#qwertmax's answer almost works. I have successfully logged in by vk, but my code prints empty lines instead of userId and another user information:
accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(r.URL.String())
fmt.Println(accessToken)
fmt.Println(userId)
fmt.Println(expiresIn)
package main
import (
"fmt"
"github.com/go-martini/martini"
"github.com/yanple/vk_api"
"net/http"
)
var api vk_api.Api
func prepareMartini() *martini.ClassicMartini {
m := martini.Classic()
m.Get("/vk/auth", func(w http.ResponseWriter, r *http.Request) {
var api vk_api.Api
authUrl, err := api.GetAuthUrl("http://localhost:3000/vk/token", "token", "2756549", "wall,offline")
fmt.Println(authUrl)
if err != nil {
panic(err)
}
http.Redirect(w, r, authUrl, http.StatusFound)
})
m.Get("/vk/token", func(w http.ResponseWriter, r *http.Request) {
accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(r.URL.String())
if err != nil {
panic(err)
}
fmt.Println(accessToken)
fmt.Println(userId)
fmt.Println(expiresIn)
})
return m
}
func main() {
prepareMartini().Run()
}
for you VK settings you have to add your domain like on this screenshot
After that you will be redirected to http://localhost:3000/vk/token#access_token=some_token&expires_in=0&user_id=0000000
but I'm not sure how you will Parse url via "ParseResponseUrl" because vk get to you "fragment url".
Fragment url is not sending to serve via HTTP - I think that could be a problem.
Thanks for answer,
I added example #qwertmax and fixed bug for parse fragment of url. Please update package and see example.
package main
// Thanks #qwertmax for this example
// (http://stackoverflow.com/questions/29359907/social-network-vk-auth-with-martini)
import (
"log"
"github.com/go-martini/martini"
"github.com/yanple/vk_api"
"net/http"
)
var api vk_api.Api
func prepareMartini() *martini.ClassicMartini {
m := martini.Classic()
m.Get("/vk/auth", func(w http.ResponseWriter, r *http.Request) {
authUrl, err := api.GetAuthUrl(
"http://localhost:3000/vk/token",
"app client id",
"wall,offline")
if err != nil {
panic(err)
}
http.Redirect(w, r, authUrl, http.StatusFound)
})
m.Get("/vk/token", func(w http.ResponseWriter, r *http.Request) {
code := r.URL.Query().Get("code")
err := api.OAuth(
"http://localhost:3000/vk/token", // redirect uri
"app secret key",
"app client id",
code)
if err != nil {
panic(err)
}
http.Redirect(w, r, "/", http.StatusFound)
})
m.Get("/", func(w http.ResponseWriter, r *http.Request) string {
if api.AccessToken == "" {
return "<a href='/vk/auth'>Авторизоваться</a>"
}
// Api have: AccessToken, UserId, ExpiresIn
log.Println("[LOG] martini.go:48 ->", api.AccessToken)
// Make query
params := make(map[string]string)
params["domain"] = "yanple"
params["count"] = "1"
strResp, err := api.Request("wall.get", params)
if err != nil {
panic(err)
}
return strResp
})
return m
}
func main() {
prepareMartini().Run()
}
Update 1:
Update your package with command: go get -u github.com/yanple/vk_api
Thanks for the comment.
In the package documentation, YourRedirectFunc is intended as placeholder for the actual method used to redirect a request in your particular case. It could be http.Redirect for example. Same for getCurrentUrl.
In fact, the example you linked to should be written as two handlers for your martini instance:
// This handler redirect the request to the vkontact system, which
// will perform the authentification then redirect the request to
// the URL we gave as the first paraemeter of the GetAuthUrl method
// (treated by the second handler)
m.Get("/vk/auth", func(w http.ResponseWriter, r *http.Request) {
var api vk_api.Api
authUrl, err := api.GetAuthUrl("domain.com/vk/token", "token", "4672050", "wall,offline")
if err != nil {
panic(err)
}
http.Redirect(w, r, authUrl, http.Found)
})
// This handler is the one that get the actual authentification
// information from the vkontact api. You get the access token,
// userid and expiration date of the authentification session.
// You can do whatever you want with them, generally storing them
// in session to be able to get the actual informations later using
// the access token.
m.Get("/vk/token", func(w http.ResponseWriter, r *http.Request) {
accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(r.URL.String())
if err != nil {
panic(err)
}
})

Resources