Deep-dive on the Next Gen Platform. Join the Webinar!

Skip Navigation
Show nav
Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
    • .NET
  • 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
Hide categories

Categories

  • Heroku Architecture
    • Compute (Dynos)
      • Dyno Management
      • Dyno Concepts
      • Dyno Behavior
      • Dyno Reference
      • Dyno Troubleshooting
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Developer Tools
    • Command Line
    • Heroku VS Code Extension
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery & Integration (Heroku Flow)
    • Continuous Integration
  • Language Support
    • Node.js
      • Working with Node.js
      • Node.js Behavior in Heroku
      • Troubleshooting Node.js Apps
    • Ruby
      • Rails Support
      • Working with Bundler
      • Working with Ruby
      • Ruby Behavior in Heroku
      • Troubleshooting Ruby Apps
    • Python
      • Working with Python
      • Background Jobs in Python
      • Python Behavior in Heroku
      • Working with Django
    • Java
      • Java Behavior in Heroku
      • Working with Java
      • Working with Maven
      • Working with Spring Boot
      • Troubleshooting Java Apps
    • PHP
      • PHP Behavior in Heroku
      • Working with PHP
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
    • .NET
      • Working with .NET
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
      • Migrating to Heroku Postgres
    • Heroku Key-Value Store
    • Apache Kafka on Heroku
    • Other Data Stores
  • AI
    • Working with AI
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
      • Single Sign-on (SSO)
    • Private Spaces
      • Infrastructure Networking
    • Compliance
  • Heroku Enterprise
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
  • 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 February 13, 2025

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.

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.

Creating the Resource Token

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

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, 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 Deprovisioning of Add-ons (Public Beta)

Information & Support

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

Language Reference

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

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing
  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Github
  • LinkedIn
  • © 2025 Salesforce, Inc. All rights reserved. Various trademarks held by their respective owners. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States
  • heroku.com
  • Legal
  • Terms of Service
  • Privacy Information
  • Responsible Disclosure
  • Trust
  • Contact
  • Cookie Preferences
  • Your Privacy Choices