This part of the Go Bookshelf tutorial shows how to create a sign-in flow for users and how to use profile information to provide users with personalized functionality.
By using Google Identity Platform, you can easily access information about your users while ensuring their sign-in credentials are safely managed by Google. OAuth 2.0 makes it easy to provide a sign-in flow for all users of your app and provides your application with access to basic profile information about authenticated users.
This page is part of a multi-page tutorial. To start from the beginning and read the setup instructions, go to Go Bookshelf app.
Creating a web application client ID
A web app client ID lets your app authorize users and access Google APIs on behalf of your users.
In the Google Cloud Platform Console, go to Credentials.
Click OAuth consent screen. For the product name, enter
Go Bookshelf App.For Authorized Domains, add your App Engine app name as
[YOUR_PROJECT_ID].appspot.com. Replace[YOUR_PROJECT_ID]with your GCP project ID.Fill in any other relevant, optional fields. Click Save.
Click Create credentials > OAuth client ID.
In the Application type drop-down list, click Web Application.
In the Name field, enter
Go Bookshelf Client.In the Authorized redirect URIs field, enter the following URLs, one at a time.
http://localhost:8080/oauth2callback
http://[YOUR_PROJECT_ID].appspot.com/oauth2callback
https://[YOUR_PROJECT_ID].appspot.com/oauth2callback
Click Create.
Copy the client ID and client secret and save them for later use.
Configuring settings
Go to the directory that contains the sample code:
Linux/macOS
cd $GOPATH/src/github.com/GoogleCloudPlatform/golang-samples/getting-started/bookshelfWindows
cd %GOPATH%\src\github.com\GoogleCloudPlatform\golang-samples\getting-started\bookshelfOpen
config.gofor editing.Uncomment this line:
// oauthConfig = configureOAuthClient("clientid", "clientsecret")Replace
"clientid"and"clientsecret"with the client ID and client secret you created previously.Save and close
config.go.Edit
app/app.yaml. In theOAUTH2_CALLBACKenvironment variable, replace<your-project-id>with your project ID.
Running the app on your local machine
Run the app to start a local web server:
cd app go run app.go auth.go template.goEnter this address in your web browser:
Press Control+C to exit the local web server.
Deploying the app to the App Engine flexible environment
In the
appdirectory, enter this command to deploy the sample:gcloud app deployIn your web browser, enter this address. Replace
[YOUR_PROJECT_ID]with your project ID:https://[YOUR_PROJECT_ID].appspot.com
If you update your app, you can deploy the updated version by entering the same command you used to deploy the app the first time. The new deployment creates a new version of your app and promotes it to the default version. The older versions of your app remain, as do their associated VM instances. Be aware that all of these app versions and VM instances are billable resources.
You can reduce costs by deleting the non-default versions of your app.
To delete an app version:
- In the GCP Console, go to the Versions page for App Engine.
- Select the checkbox for the non-default app version you want to delete.
- Click Delete deleteto delete the app version.
For complete information about cleaning up billable resources, see the Cleaning up section in the final step of this tutorial.
Application structure
The following diagram shows the application's components and how they connect to one another.

Understanding the code
This section walks you through the application code and explains how it works.
About sessions
Before your application can authenticate users, you need a way to store
information about the current user in a session. The
Gorilla web toolkit
includes a
Store
interface, which includes several implementations. The CookieStore
implementation stores session data in a secure cookie, and the FilesystemStore
implementation stores session data on the file system.
Storing session data on the file system is unsuitable for an application
that can be served from multiple VM instances, as the session that is recorded
in one instance might differ from other instances. For this reason, the
Bookshelf sample uses encrypted cookies (CookieStore). The encrypted session
data is stored in the user's browser and can be decrypted by any instance
running the application code. The CookieStore implementation can be used in
production environments where you have deployed multiple instances of your
application, but be aware that users will lose their session information when
they close the browser.
Authenticating users
Authenticating the user involves two basic steps, which together are called the web service flow.
- Redirect the user to Google’s authorization service.
- Process the response when Google redirects the user back to your application.
Here we describe the two steps in detail:
Redirect to Google.
Your application sends the user to Google’s authorization service. The application generates a URL by using your client ID and the OAuth scopes that the application uses. Scopes indicate which items of the user’s information your application is allowed to access. There are multiple Google services, with different scopes for each service. For example, there is a scope that allows read-only access to Google Drive and another scope that allows read/write access. This sample requires only the basic scopes
emailandprofile, which grant the application access to the user's email address and basic profile information:The
loginHandlerfunction redirects the/loginURL path to the Google authorization service:The first parameter of the
AuthCodeURLfunction is thestateparameter. This is used to keep the sign-in process secure by preventing cross-site request forgery.Your application redirects the user to the generated URL. The user is prompted to allow your application to access the scopes you specified. After the user accepts, they are redirected back to your application.
Process the authorization response.
The Google authorization service sends the user back to your application via the
/oauth2callbackURL path along with the authorization code specified by thecodeform value. This code can be exchanged, along with your client secrets, to obtain the user’s credentials and information about the user. This step of the flow happens entirely server-side without having to redirect the user. This extra step is required to verify the authenticity of the authorization code and that your application is the one requesting credentials:After you obtain the user's credentials, you can retrieve their profile information via the Google+ API. The call to
plusService.People.Get("me")retrieves the profile for the currently authenticated user. The profile is stored in the session against thegoogleProfileSessionKey(encoded usingencoding/gob):Because the profile information is stored in the session, it can be retrieved by the application without fetching it again from the Google+ API.
For example, the profile is passed into the base template to render the signed-in user's name and profile photo on every page:
Personalization
Now that you have the signed-in user's information available through middleware, you can keep track of which user added which book to the database.
And because that information is stored in the database, you can show the user which books they have personally added.
This code uses a database method called ListBooksCreatedBy. The implementation
depends on which database backend you chose.
Datastore
In Cloud Datastore, you need to create additional indexes for a query that
filters over more than one field. This query, in the ListBooksCreatedBy
function, filters over both CreatedByID and Title.
To create the indexes, enter these commands:
Linux/macOS
cd $GOPATH/src/github.com/GoogleCloudPlatform/golang-samples/getting-started/bookshelf
cd app
gcloud datastore create-indexes index.yaml
Windows
cd %GOPATH%\src\github.com\GoogleCloudPlatform\golang-samples\getting-started\bookshelf
cd app
gcloud datastore create-indexes index.yaml


