Skip Navigation
Show nav
Heroku Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
View categories

Categories

  • Heroku Architecture
    • Dynos (app containers)
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Command Line
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery
    • Continuous Integration
  • Language Support
    • Node.js
    • Ruby
      • Working with Bundler
      • Rails Support
    • Python
      • Background Jobs in Python
      • Working with Django
    • Java
      • Working with Maven
      • Java Database Operations
      • Working with Spring Boot
      • Java Advanced Topics
    • PHP
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
    • Heroku Data For Redis
    • Apache Kafka on Heroku
    • Other Data Stores
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
    • Compliance
  • Heroku Enterprise
    • Private Spaces
      • Infrastructure Networking
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
    • Single Sign-on (SSO)
  • Patterns & Best Practices
  • Extending Heroku
    • Platform API
    • App Webhooks
    • Heroku Labs
    • Building Add-ons
      • Add-on Development Tasks
      • Add-on APIs
      • Add-on Guidelines & Requirements
    • Building CLI Plugins
    • Developing Buildpacks
    • Dev Center
  • Accounts & Billing
  • Troubleshooting & Support
  • Integrating with Salesforce
  • Language Support
  • Go
  • OAuth2 with Heroku & Go

OAuth2 with Heroku & Go

English — 日本語に切り替える

Last updated January 26, 2022

Table of Contents

  • Prerequisites
  • The sample application
  • OAuth Client Setup
  • App Setup
  • Global Variables
  • init function
  • Handlers
  • main function
  • Visiting the App
  • Summary

This tutorial demonstrates how to create a web application on Heroku that lets users authorize using the Heroku platform’s OAuth API, and then perform API calls to api.heroku.com. It can serve as the basis of a more complex integration scenario.

The tutorial uses the Go language, but the main concepts, configuration and architecture can be just as easily applied to any other language supported by Heroku.

Sample code for the demo application is available on GitHub. Edits and enhancements are welcome. Just fork the repository, make your changes and send us a pull request.

Prerequisites

  • A Heroku user account. Signup is free and instant.
  • If you haven’t already, follow Getting Started with Go on Heroku to familiarize yourself with Heroku.

The sample application

The sample app demonstrates the main components of authorization and making API calls. The rest of this tutorial will highlight various parts of the app.

To get started, clone the application:

$ go get -u github.com/heroku-examples/heroku-oauth-example-go
$ cd $GOPATH/src/github.com/heroku-examples/heroku-oauth-example-go

OAuth Client Setup

$ heroku clients:create  "Go OAuth Example ($USER)" https://go-heroku-oauth-example-$USER.herokuapp.com/auth/heroku/callback

Note the provided HEROKU_OAUTH_ID and HEROKU_OAUTH_SECRET output, this is used below. These are used to identify and authenticate the sample application to heroku.

App Setup

$ heroku create go-heroku-oauth-example-$USER
$ heroku labs:enable runtime-dyno-metadata
$ heroku config:add HEROKU_OAUTH_ID=<value from above>
$ heroku config:add HEROKU_OAUTH_SECRET=<value from above>
$ heroku config:add COOKIE_SECRET=`openssl rand -hex 32`
$ heroku config:add COOKIE_ENCRYPT=`openssl rand -hex 16`
$ git push heroku master
$ heroku open

The COOKIE_* config vars are used to secure the cookies created by the sample app.

At this point you should have a working application and your web browser open to a page that says “Sign in with Heroku”.

Before continuing let’s look at the code behind the sample application.

Global Variables

Since this is a simple example application it uses a few global variables. In a normal application these would be defined on a struct implementing http.Handler or a similar, framework specific struct.

var (
    store = sessions.NewCookieStore([]byte(os.Getenv("COOKIE_SECRET")), []byte(os.Getenv("COOKIE_ENCRYPT")))

    oauthConfig = &oauth2.Config{
        ClientID:     os.Getenv("HEROKU_OAUTH_ID"),
        ClientSecret: os.Getenv("HEROKU_OAUTH_SECRET"),
        Endpoint:     heroku.Endpoint,
        Scopes:       []string{"identity"},
        RedirectURL:  "http://" + os.Getenv("HEROKU_APP_NAME") + "herokuapp.com/auth/heroku/callback",
    }

    stateToken = os.Getenv("HEROKU_APP_NAME")
)

func init() {
    gob.Register(&oauth2.Token{})

    store.MaxAge(60 * 60 * 8)
    store.Options.Secure = true
}

store is a cookie based session store. The sample app saves it’s intermediate data in a secure cookie.

oauthConfig is an oauth2.Config setup for your instance of the sample application. You can find more information about supported scopes here.

stateToken is used during the ouath2 handshake.This would normally be set to an opaque value that can be checked by the applications during the oauth2 handshake.

init function

The init function:

  1. Registers the oauth2.Token type with gob so the token we receive can be serialized into a cookie later.
  2. Sets up the store to expire in 8 hours and ensures that cookies are only sent via https.

Handlers

func handleRoot(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, `<html><body><a href="/auth/heroku">Sign in with Heroku</a></body></html>`)
}

The handleRoot function displays our simple index page.

func handleAuth(w http.ResponseWriter, r *http.Request) {
    url := oauthConfig.AuthCodeURL(stateToken)
    http.Redirect(w, r, url, http.StatusFound)
}

The handleAuth function uses oauthConfig to create an url pointing to Heroku’s consent page and then redirects the user to this page. This is the first part of the OAuth interaction.

func handleAuthCallback(w http.ResponseWriter, r *http.Request) {
    if v := r.FormValue("state"); v != stateToken {
        http.Error(w, "Invalid State token", http.StatusBadRequest)
        return
    }
    ctx := context.Background()
    token, err := oauthConfig.Exchange(ctx, r.FormValue("code"))
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    session, err := store.Get(r, "heroku-oauth-example-go")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    session.Values["heroku-oauth-token"] = token
    if err := session.Save(r, w); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    http.Redirect(w, r, "/user", http.StatusFound)
}

The handleAuthCallback is the second and core part of the OAuth interaction. First the state form value is retrieved and checked against the set stateToken. If it’s not the same, the request is bad. Next the app uses the background context (In a real application an application specific context would be used.) to perform the OAuth2 exchange, converting the provided code to a token. Next the app stores the token in session and save the session into the cookie. Last we’re redirected to the /user route.

func handleUser(w http.ResponseWriter, r *http.Request) {
    session, err := store.Get(r, "heroku-oauth-example-go")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    token, ok := session.Values["heroku-oauth-token"].(*oauth2.Token)
    if !ok {
        http.Error(w, "Unable to assert token", http.StatusInternalServerError)
        return
    }
    client := oauthConfig.Client(context.Background(), token)
    resp, err := client.Get("https://api.heroku.com/account")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    defer resp.Body.Close()
    d := json.NewDecoder(resp.Body)
    var account struct { // See https://devcenter.heroku.com/articles/platform-api-reference#account
        Email string `json:"email"`
    }
    if err := d.Decode(&account); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    fmt.Fprintf(w, `<html><body><h1>Hello %s</h1></body></html>`, account.Email)
}

The handleUser function shows how to use the oauth2.Client method paired with a token to call the Heroku API. The function starts out by retrieving the token from the session. Next it creates a http.Client using the [oauth2.Client](https://godoc.org/golang.org/x/oauth2#Config.Client) method to fetch the user’s account information from the Heroku API. Last it says hello to the user.

func main() {
    http.HandleFunc("/", handleRoot)
    http.HandleFunc("/auth/heroku", handleAuth)
    http.HandleFunc("/auth/heroku/callback", handleAuthCallback)
    http.HandleFunc("/user", handleUser)
    http.ListenAndServe(":"+os.Getenv("PORT"), nil)

main function

The main function is your entry point into the program and wires up the above handlers into the default http Mux and starts a http server on $PORT.

Visiting the App

When you click on Sign in with Heroku, your browser requests /auth/heroku, which generates the oauth2 provider URL and redirects you to https://id.heroku.com for login. Once you have authorized your instance of the sample app, id.heroku.com redirects you back to your sample app’s /auth/heroku/callback with the appropriate oauth2 state and code parameters. And finally this redirects you to a page that says Hello <your email address>.

Summary

This tutorial demonstrates how to create a Heroku web application that uses Heroku’s OAuth2 API for authentication and how to then use the provided OAuth2 token to authenticate to Heroku’s API.

Keep reading

  • Go

Feedback

Log in to submit feedback.

Using WebSockets on Heroku with Go Scaling a Gin Application with Memcache

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Podcasts
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing

Subscribe to our monthly newsletter

Your email address:

  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Heroku Podcasts
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Facebook
  • Instagram
  • Github
  • LinkedIn
  • YouTube
Heroku is acompany

 © Salesforce.com

  • heroku.com
  • Terms of Service
  • Privacy
  • Cookies
  • Cookie Preferences