马丁尼社交网络vk auth

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)

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)
    }
})
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.