Asgardeo authentication with Golang and Goth

Wathsara Wishwantha Daluwatta
5 min readJan 22, 2022

With this blog I will focus on implementing authentication via Asgardeo in a Go web application. For this you need to have the basic knowledge on GO, HTML and CSS. As Asgardeo has not yet released an official Golang SDK yet, I will be using the Goth which is an open source Multi-Provider Authentication package for Golang.

Step 1 — Register an OpenID application in Asgardeo.

  1. Login to Asgardeo Console.
  2. Go to Develop section and then select Applications.
  3. Click New Application.
  4. Choose Traditional Web Application and Choose OpenID Connect.
  5. Provide any application name and configure http://localhost:8000/auth/openid-connect/callback and http://localhost:8000/logout/openid-connect as the Authorized redirect URLs (If you are planning to run on a different port, update the callback URLs with your port) and click Register.

6. Then go to Protocol tab and obtain a Client ID and Client Secret.

7. Then add http://localhost:8000 in the allowed origins field and update the application.

Step 2 —Create a customer user in Asgardeo.

  1. Go to Manage section and then select Users.
  2. Click New User and select Customer.
  3. Enter the customer Email, First Name, Last Name and select Set a temporary password for user and enter a password and then click Finish.

Step 3 — Initialize a Go project.

Go to a new directory and execute the following command. It will create a new go.mod which will help us to manage the dependencies easily.

go mod init asgardeo

If your are new to Golang please follow this article to create your first project.

Step 4 — Implement the Golang server.

Following are the main packages that we’ll be using for the implementation.

  • html/template: Go package to parse html files.
  • gorilla/pat: A request router and dispatcher.
  • gorilla/sessions: To save information from asgardeo in session.
  • markbates/goth/providers/openidConnect: OpenID connect provider provider by Goth.

First we need to initialize a session store called NewCookieStore() provided by the gorilla/sessions and pass a secret key used to authenticate the session. Inside the handler, we call store.Get() to retrieve an existing session or create a new one. Then we set some session values in session.Values, which is a map[interface{}]interface{}. And finally we call session.Save() to save the session in the response. Then we can set this as the gothic store to manage the session. We can do it by adding the following code to main.go.

var key = “_auth_session” // Note: Don't store your key in your source code.
var store = sessions.NewCookieStore([]byte(key))
var sessionName = “auth”
func main() { store.MaxAge(3600)
store.Options.Path = “/"
store.Options.HttpOnly = true
gothic.Store = store
}

Then we need to set up the Openid connect configuration by adding the following code in the main function of the main.go

// Export these to enviroment varibles with your valus.
OPENID_CONNECT_KEY := os.Getenv(“OPENID_CONNECT_KEY”)
OPENID_CONNECT_SECRET := os.Getenv(“OPENID_CONNECT_SECRET”)
ASGARDEO_ORG_NAME = os.Getenv(“ASGARDEO_ORG_NAME”)
CALLBACK_URL := “http://localhost:8000/auth/openid-connect/callback"OPENID_CONNECT_DISCOVERY_URL := fmt.Sprintf(“https://api.asgardeo.io/t/%s/oauth2/token/.well-known/openid-configuration", ASGARDEO_ORG_NAME)openidConnect, _ := openidConnect.New(OPENID_CONNECT_KEY, OPENID_CONNECT_SECRET, CALLBACK_URL, OPENID_CONNECT_DISCOVERY_URL)if openidConnect != nil {
goth.UseProviders(openidConnect)
}

Then we will create the Go server with the following routes. We will be using the gorilla/pat for routing. Include the following code in the main method as well.

router := pat.New()
router.Get(“/auth/{provider}/callback”, callback)
router.Get(“/auth/{provider}”, auth)
router.Get(“/logout/{provider}”, logout)
router.Get(“/home”, home)
router.Get(“/”, indexHandler)
http.Handle(“/”, router)
log.Print(“Listening on port 8000…”)
log.Fatal(http.ListenAndServe(“:8000”, nil))

Create a separate directory named ui to include the HTML files that are needed for our web application.

Add the following code to a file named index.html.

Create another file in the ui directory with name home.html and include the following code into the file. This will show the decorded ID token after successful authentication.

Let’s start to implement the rest of the functions.

  • “/”: The root route will render the index.html page. This page will include the SignIn button.
func indexHandler(wr http.ResponseWriter, req *http.Request){

wr.WriteHeader(http.StatusOK)
t, _ := template.ParseFiles(“ui/index.html”)
t.Execute(wr, false)
}
  • /auth/{provider}: When you click on SignIn button it will hit this route and gothic.BeginAuthHandler will redirect you to the Asgardeo for the authentication.
func auth(wr http.ResponseWriter, req *http.Request) {    gothic.BeginAuthHandler(wr, req)
}
  • /auth/{provider}/callback: Once you have authenticated, gothic.CompleteUserAuth will capture the relevant information from the callback. This is why we initially configured the callback URL with http://localhost:8000/auth/openid-connect/callback. Then goth will save the information in session to use when the web application wants.
func callback(wr http.ResponseWriter, req *http.Request) {     user, err := gothic.CompleteUserAuth(wr, req)
if err != nil {
wr.WriteHeader(http.StatusInternalServerError)
log.Print(err)
return
}
addUserToSession(wr, req, user)
http.Redirect(wr, req, "/home", http.StatusFound)
}
  • “/home”: The route will render the home.html page. This page will include the information of the jwt token.
func home(wr http.ResponseWriter, req *http.Request) {   session, _ := store.Get(req, sessionName)
user := session.Values["user"].(goth.User)
if user.IDToken == "" {
wr.Header().Set("Location", "/")
wr.WriteHeader(http.StatusTemporaryRedirect)
return
}
t, _ := template.ParseFiles("ui/home.html")
t.Execute(wr, struct {
Org string
IDToken string
}{ASGARDEO_ORG_NAME, user.IDToken})
}
  • /logout/{provider}: This route will be use to remove the session. Users will be redirected to this route from the post logout redirect url from the asgardeo. That’s why we configured the call back URL with http://localhost:8000/logout/openid-connect.
func logout(wr http.ResponseWriter, req *http.Request) {

err := gothic.Logout(wr, req)
if err != nil {
log.Print("Logout fail", err)
}
removeUserFromSession(wr, req)
wr.Header().Set("Location", "/")
wr.WriteHeader(http.StatusTemporaryRedirect)
}

It’s time for the demonstration.

Great…!!

Here you have implemented Asgardeo authentication with Golang. Now you could follow https://wso2.com/asgardeo/docs and customize the logins as you wish within minutes.

If you want to tryout the sample please use the following command.

docker run -e OPENID_CONNECT_KEY=<YOUR_APP_KEY> \
-e OPENID_CONNECT_SECRET=<YOUR_APP_SECRET> \
-e ASGARDEO_ORG_NAME=<YOUR_ORG_NAME> \
-p 8000:8000 wathsara/asgardeo-go-sample-app:1.0.0

You can find the sample application with full code base from below GitHub repository.

Thank you for reading my article. Have a Good Day!!

References

https://wso2.com/asgardeo/docs

--

--

Wathsara Wishwantha Daluwatta

Software Engineer at WSO2 | Studied BSc (Hons) Software Engineering at University of Colombo School of Computing