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 the Play Framework
      • 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
  • Extending Heroku
  • Building Add-ons
  • Add-on Development Tasks
  • Add-on Single Sign-on

Add-on Single Sign-on

English — 日本語に切り替える

Last updated July 13, 2020

Table of Contents

  • Summary
  • Testing SSO
  • Salt, timestamp, and tokens
  • Signing in the user on redirect
  • Display user information in your site’s layout
  • Sample code
  • Removing non-relevant page elements

Your cloud service probably has a web UI admin panel that your users log into to manage their resources. For example, a Memcache cloud service may offer a dashboard for web-based usage analytics and the ability to flush a cache.

Heroku customers can access your dashboard as well if you implement single sign-on as described in this document.

This article documents how to implement SSO under the current v3 of the Add-on Partner API, and most examples reflect as such. We’ve noted the differences for legacy v1 integrations where necessary. You can find the API version your add-on is using in the Partner Portal under “Settings” -> “Provisioning API”.

Summary

Heroku will generate a single sign-on token by combining the salt (a shared secret), timestamp, and resource ID. The user’s browser will be redirected to your site with this token. Your site can confirm the authenticity of the token, then create a user session and route them to the admin panel for their resource.

Testing SSO

We suggest creating a <your slug>-staging version of your add-on to test SSO and other add-on integration features. This <your slug>-staging add-on should point to staging versions of your integration infrastructure.

Salt, timestamp, and tokens

The add-on manifest is a JSON document that describes your add-on.

When you create an add-on (and consequently its manifest), the manifest fields include a randomly-generated sso_salt.

There are two tokens in an SSO request and either one may be used to log in the user, depending on what version of the Add-on Partner API you’re using. The v3 token is named resource_token. The legacy v1 token is named token.

Creating the Resource Token under v3

Under v3 of the Add-on Partner API, the resource_token is created using the following formula:

resource_token = sha1(resource_uuid + ':' + salt + ':' + timestamp)
  • resource_uuid is the uuid that we provide for the resource in a provisioning request.
  • salt comes from your add-on manifest.
  • timestamp will be included in the parameters for the POST request.

For example, given these inputs:

resource_uuid = 11111111-1111-1111-1111-111111111111
salt = 2f97bfa52ca102f8874716e2eb1d3b4920ad0be4
timestamp = 1267597772

…the SSO resource_token will be:

SHA1("11111111-1111-1111-1111-111111111111:2f97bfa52ca102f8874716e2eb1d3b4920ad0be4:1267597772") =
4e9ce13ca328c6f3e2857b7de1724fd6c7c1c423

Creating the Resource Token under v1

Under v1 of the Add-on Partner API, the token is created using the following formula:

token = sha1(provider_id + ':' + salt + ':' + timestamp)
  • provider_id is the value you created and returned from your cloud service during a response to provisioning request.
  • salt comes from your add-on manifest.
  • timestamp will be included in the parameters for the POST request.

For example, given these inputs:

provider_id = 123
salt = 2f97bfa52ca102f8874716e2eb1d3b4920ad0be4
timestamp = 1267597772

…the SSO token will be:

SHA1("123:2f97bfa52ca102f8874716e2eb1d3b4920ad0be4:1267597772") =
bb466eb1d6bc345d11072c3cd25c311f21be130d

Signing in the user on redirect

When the user clicks your add-on in their add-on menu, they will be directed via HTTP POST to a URL defined in your manifest.

Requests will look like:

POST <production/sso_url>
resource_id=<resource_id>&resource_token=<resource_token>&id=<id>&token=<token>&timestamp=<timestamp>&nav-data=<nav data>&email=<user's email address>

As shown, the data is form-encoded in the POST body.

  • sso_url comes from your add-on manifest.
  • resource_id is the uuid that we provide for the resource in the provisioning call.
  • timestamp is a unix epoch timestamp.
  • resource_token is computed using the formula above. When using the resource_id and resource_token, the id and token values should be ignored.

Legacy fields that can safely be ignored are:

  • id and token – used only for the v1 salted token. Ignore if you are on v3 of the Add-on Partner API.
  • nav-data contains information like the current app name and installed add-ons so the Heroku layout can build the appropriate view for the current app.

If the SHA1 hash you compute does not match the one passed in resource_token (or token if you’re using v1), the user should be shown a page with an HTTP status code of 403. If the timestamp is older than five minutes, they should also see a 403.

HTTP status code 403 indicates that the user was not allowed access to this page. You can return this code and still render a normal, human-readable page for them, perhaps suggesting that they contact support if they believe their request is legitimate.

If the timestamp is current and the SHA1 hash matches, the user is authorized to access the resource in question.

You should create a user session through whatever method you normally use, possibly setting a cookie. The session should also store that it is a Heroku single sign-on, since what is displayed will be slightly different for Heroku customers than users logging in through your regular standalone service. Because user access can change at any time this SSO data should only be trusted for the duration of a session. We also suggest limiting session lifespan to 90 minutes.

Display user information in your site’s layout

There are additional form-encoded parameters sent in the SSO request to help your site display a context for the user. These include:

  • user - the email address of the current user
  • app - the Heroku app name that is in scope and the user came from.

These can be used to populate a template for the user info (and potentially fetch their Gravatar) as well as link back to the Dashboard for the app in context. For that, assuming the param came in as &app=your-app-name, link to https://dashboard.heroku.com/apps/your-app-name.

Sample code

Here’s a sample implementation of a v3 single sign-on endpoint written in Ruby/Sinatra:

post "/heroku/sso" do
  pre_token = params[:resource_id] + ':' + HEROKU_SSO_SALT + ':' + params[:timestamp]
  token = Digest::SHA1.hexdigest(pre_token).to_s
  halt 403 if token != params[:resource_token]
  halt 403 if params[:timestamp].to_i < (Time.now - 2*60).to_i

  account = Account.find(params[:resource_id])
  halt 404 unless account

  session[:user] = account.id
  session[:heroku_sso] = true
  redirect "/dashboard"
end

Removing non-relevant page elements

Once you have your site accepting single sign-on requests, the final step is to hide (or disable) page elements that are not relevant for Heroku customer SSO sessions. Some examples include:

  • Change password
  • Change account name
  • Update billing information
  • Log out

Heroku customers will manage all of these items through the Heroku Dashboard and CLI, and your add-on cannot update them in Heroku’s infrastructure.

Keep reading

  • Add-on Development Tasks

Feedback

Log in to submit feedback.

Writing to Application Logs as an Add-on Partner Asynchronous Provisioning of Add-ons

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