2

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)
Community
  • 1
  • 1
Maxim Yefremov
  • 13,671
  • 27
  • 117
  • 166

3 Answers3

2
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

enter image description here

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.

qwertmax
  • 3,120
  • 2
  • 29
  • 42
  • Thank you, I have logged in, but code prints empty lines `fmt.Println(accessToken) fmt.Println(userId) fmt.Println(expiresIn) `. Please see `update 2` above – Maxim Yefremov Apr 08 '15 at 13:29
  • yeah, see the end of my answer - it's because vk response has fragment url, #access_token .... etc, they are NOT visible for backend (for your server) – qwertmax Apr 08 '15 at 13:36
  • if you print r.URL.String() you'll see just /vk/token because everything after # in url will stay on browser side (frontend) – qwertmax Apr 08 '15 at 13:38
  • so seemingly, the only one solution is to use javascript to get `access_token` like `document.location.hash` – Maxim Yefremov Apr 08 '15 at 13:54
  • yeah, any js solutions will 100% works. I don't know the aim of you project, and I can't advice you what could works for you. – qwertmax Apr 08 '15 at 13:55
  • the aim of current code piece is to provide logining by vk, then just get Name and Vk UserId. – Maxim Yefremov Apr 08 '15 at 13:58
  • ah, I see. I think that go vk api it not best solution to use ;) It is simple oauth you can find a lot of projects on github – qwertmax Apr 08 '15 at 14:07
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/74780/discussion-between-efr-and-qwertmax). – Maxim Yefremov Apr 09 '15 at 03:20
1

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.

happierall
  • 91
  • 4
0

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)
    }
})
Elwinar
  • 9,103
  • 32
  • 40