Skip to content

Programming can be cute.

  • LinkedIn
  • GitHub Profile
  • Stack Overflow Profile
  • About Me

cuteprogramming

  • Home
  • About
  • Experience
  • Product
  • Event

Tag: Google Sign-In

Authenticating Users in Golang Web App

April 7, 2019April 7, 2019 by Chun Lin, posted in Experience, Go (Golang), OAuth, Security

Continue from the previous topic…

Without user authentication, we cannot secure our web services and protect our users’ privacy on our application. Hence, it is important to introduce ways to authenticate users in our Golang web application now.

In this article, we will focus only on authenticating users on our Golang web application with Google Sign-In in Google Identity Platform.

Configure OAuth on Google Cloud Platform

We first need to create a Project on Google Cloud Platform (GCP).

After the Project is created successfully, we need to proceed to OAuth Consent Screen to enter the information of our Golang web application, as shown in the following screenshot.

Setting up the OAuth consent screen for our Golang web application.

As you should have noticed by now, we are using OAuth because OAuth authentication system from Google makes it easy to provide a sign-in flow for all users of our application and provides our application with access to basic profile information about authenticated users.

Currently, Google only allows applications that authenticate using OAuth to use Authorized Domains which are required for redirect or origin URIs. Another thing to take note is that Authorized Domains must be a Top Private Domain. Hence, even though azurewebsites.net is a top level domain but it is not privately owned, so we cannot use the default Azure Web App URL. We thus need to assign a domain which is owned by us.

After entering all the information, we can then submit for verification. Interestingly, the verification step is not compulsory. We can choose to just save the information without submitting it for verification. However, users of unverified web applications might get warnings based on the OAuth scopes we’re using. This is how Google protects users and their data from deceptive applications.

We will then be able to get both Client ID and Client Secret of our OAuth client for later use, as shown in the screenshot below.

Client ID and Client Secret of the OAuth client.

Configure Settings in Golang Web Application

With the configuration done on GCP, we can then move on to update our Golang web application. Fortunately, Google provides a code sample about authenticating users with Go.

Application structure.

There is Sessions in the graph above because we need a way to store information about the current user. To do so, we make use of the CookieStore implementation to store session data in a secure cookie.

There are basically two new files need to be introduced.

Firstly, we have auth.go which is in charge of handling login/logout requests, handling callback from the OAuth, fetching user profile, and validating redirect URL to make sure there will be no attempts to redirect users to a path not existing within the web application.

Secondly, we have config.go which has all the configuration needed for the OAuth client on our web application. The two main functions are as follows. So this is the part when the Client ID and Client Secret from the GCP will be used.

func init() {
    // To enable user sign-in
    OAuthConfig = configureOAuthClient(os.Getenv("OAUTH_CLIENT_ID"), os.Getenv("OAUTH_CLIENT_SECRET"))

    // Configure storage method for session-wide information.
    cookieStore := sessions.NewCookieStore([]byte(os.Getenv("COOKIE_STORE_SECRET")))
    cookieStore.Options = &sessions.Options{
        HttpOnly: true,
    }
    SessionStore = cookieStore
}

func configureOAuthClient(clientID, clientSecret string) *oauth2.Config {
    redirectURL := os.Getenv("OAUTH2_CALLBACK")
    if redirectURL == "" {
        redirectURL = "http://localhost/oauth2callback"
    }
    return &oauth2.Config{
        ClientID: clientID,
        ClientSecret: clientSecret,
        RedirectURL: redirectURL,
        Scopes: []string{"email", "profile"},
        Endpoint: google.Endpoint,
    }
}

Handlers

We will then have the following three new handlers needed in server.go.

mux.HandleFunc("/login", handleRequestWithLog(handleLoginRequest))
mux.HandleFunc("/logout", handleRequestWithLog(handleLogoutRequest))
mux.HandleFunc("/oauth2callback", handleRequestWithLog(oauthCallbackHandler))

Our index handler will be changed to the following where it will show the homepage asking for user to login if the user is not yet logged in. Otherwise, it will bring the user to the page with the player.

func index(writer http.ResponseWriter, request *http.Request) {
    user := profileFromSession(request)
    if user == nil {

        http.ServeFile(writer, request, "templates/index.html")

        writer.Header().Set("Content-Type", mime.TypeByExtension("html"))

    } else {

        http.Redirect(writer, request, "/player", http.StatusFound)

    }
}
Users can login to our Golang web application through Google Sign-In.

Updates of Web Service

We also need to update the functions that we have done earlier for HTTP methods so that each of the functions will check for the user profile first. So we need to change the function handleVideoAPIRequests() to include the following code.

func handleVideoAPIRequests(video models.IVideo) http.HandlerFunc {
    return func(writer http.ResponseWriter, request *http.Request) {
var err error

user := profileFromSession(request)

if user == nil {
err = errors.New("sorry, you are not authorized")
   writer.WriteHeader(401)

   return
}

...
}
}

The response will be HTTP 401 Unauthorized if the user profile is not found.

If the user profile is found, then we will use the updated code to retrieve only the videos added by the current user. For example, when we are updating the info of a video record, we will need to also make sure the video record belongs to the current user, as shown in the following code.

func handleVideoAPIPut(...) (err error) { 
...

err = video.GetVideo(user.ID, videoID)
   if err != nil {
// update the video record
}
}

That means, the GetVideo function needs to be updated as well, as shown below, so that it can retrieve only video related to the currently logged-in user.

// GetVideo returns one single video record based on id
func (video *Video) GetVideo(userID string, id int) (err error) {
    sqlStatement := "SELECT id, name, url FROM videos WHERE created_by = $1 AND id = $2;"

    err = video.Db.QueryRow(sqlStatement, userID, id).Scan(&video.ID, &video.Name, &video.URL)
    video.YoutubeVideoID = video.URL[32:len(video.URL)]

    return
}

References

  1. Authenticating Users with Go;
  2. [Stack Overflow] Must be a Top Private Domain;
  3. Go Bookshelf App;
  4. [GitHub] Google Cloud Platform Go Samples;
  5. [GitHub] auth.go;
  6. [GitHub] config.go;
  7. [GitHub] app.go.
Tagged Golang, Google Sign-In, OAuth2 Comments
Buy Me A Coffee

About This Blog

Recent Posts

  • A Kubernetes Lab for Massively Parallel .NET Parameter Sweeps
  • Beyond the Cert: In the Age of AI
  • The Blueprint Fallacy: A Case for Discrete Event Simulation in Modern Systems Architecture
  • Building a Gacha Bot in Power Automate and MS Teams
  • Securing APIs with OAuth2 Introspection
  • Observing Orchard Core: Traces with Grafana Tempo and ADOT
  • Observing Orchard Core: Metrics and Logs with Grafana and Amazon CloudWatch
  • From Design to Implementation: Crafting Headless APIs in Orchard Core with Apidog
  • Automate Orchard Core Deployment on AWS ECS with CloudFormation
  • When Pinecone Wasn’t Enough: My Journey to pgvector

Blogs of My Friends

Between Linux and Anime

As the blog name suggests, it is a cute blog about Linux and anime. The style of the blog has been a big influence on me. I especially like his post on "Philosophy of Doing" which is related to a famous anime, Clannad. The blogger is my SoC tutor and CVWO team leader who taught me a lot of web development skills which are even useful in my current job.

Just Another Hideout

A blog written by my SoC friend who shows great interest in games, animes, and technology products. He is famous with mental calculation, so he writes about random interesting math calculation projects done by him also.
Blog at WordPress.com.
  • Subscribe Subscribed
    • cuteprogramming
    • Join 74 other subscribers
    • Already have a WordPress.com account? Log in now.
    • cuteprogramming
    • Subscribe Subscribed
    • Sign up
    • Log in
    • Report this content
    • View site in Reader
    • Manage subscriptions
    • Collapse this bar
 

Loading Comments...