Skip Navigation
Show nav
Heroku Dev Center Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
Heroku Dev Center Dev Center
  • 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 in or Sign up
View categories

Categories

  • Heroku Architecture
    • Compute (Dynos)
      • Dyno Management
      • Dyno Concepts
      • Dyno Behavior
      • Dyno Reference
      • Dyno Troubleshooting
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Buildpacks
    • Platform Principles
  • Developer Tools
    • AI 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 Rails
      • 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
      • Working with PHP
      • PHP Behavior in Heroku
    • 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
    • Inference Essentials
    • Inference API
    • Inference Quick Start Guides
    • AI Models
    • Tool Use
    • AI Integrations
    • Vector Database
  • 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
  • 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
    • Heroku AppLink
      • Working with Heroku AppLink
      • Heroku AppLink Reference
      • Getting Started with Heroku AppLink
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
    • Other Salesforce Integrations
  • Extending Heroku
  • Building Add-ons
  • Add-on Development Tasks
  • Add-on Single Sign-on

Add-on Single Sign-on

English — 日本語に切り替える

Table of Contents [expand]

  • 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
  • Additional Reading

Last updated February 19, 2026

Your cloud service likely has a web UI admin panel that your users log into to manage their resources. For example, a Memcache cloud service can 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 generates single sign-on tokens by combining the salt (a shared secret), timestamp, resource ID, user ID, and user email. The user’s browser redirects to your site with these tokens. Your site can confirm the authenticity of the tokens, then create a user session and route them to the admin panel for their add-on resource.

Testing SSO

We suggest creating a <your slug>-staging version of your add-on to test SSO and other add-on integration features. Point this <your slug>-staging add-on 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 three tokens in an SSO request, and any may be used to log in the user, depending on what version of the Add-on Partner API you’re using. The recommended v3 token is user_scoped_resource_token. There is also resource_token available on v3, though user_scoped_resource_token is the preferred token because it includes details on the requestor.

Creating the Resource Token

Under v3 of the Add-on Partner API, we create the user_scoped_resource_token using the following formula:

user_scoped_resource_token = sha256(resource_uuid + ':' + salt + ':' + timestamp + ':' + user_uuid + ':' + user_email)
  • resource_uuid is the UUID that we provide for the resource in a provisioning request.
  • salt comes from your add-on manifest.
  • timestamp is included in the parameters for the POST request.
  • user_uuid and user_email are the UUID and email, respectively, of the user initiating the specified add-on’s SSO request.

We create the resource_token with this formula:

    resource_token = sha1(resource_uuid + ':' + salt + ':' + timestamp)

For example, given these inputs:

resource_uuid = 11111111-1111-1111-1111-111111111111
salt = 2f97bfa52ca102f8874716e2eb1d3b4920ad0be4
timestamp = 1267597772
user_uuid = 22222222-2222-2222-2222-222222222222
user_email = user_sso@heroku.com

The SSO user_scoped_resource_token is:

SHA256("11111111-1111-1111-1111-111111111111:2f97bfa52ca102f8874716e2eb1d3b4920ad0be4:1267597772:22222222-2222-2222-2222-222222222222:user_sso@heroku.com") =
3f0df24db439d7g4f3968c8ef2835ge7d8d2d534

And the SSO resource_token is:

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 get directed via HTTP POST to a URL defined in your manifest.

Requests look like:

POST <production/sso_url>
resource_id=<resource_id>&resource_token=<resource_token>&id=<id>&token=<token>&timestamp=<timestamp>&nav-data=<nav data>&user_id=<user_id>&email=<user's email address>&user_scoped_resource_token=<user_scoped_resource_token>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 get ignored.
  • user_id is the UUID that we provide for the user initiating the SSO request.
  • email is the email address of the user initiating the SSO request. Use this email address over the one provided in the navigation data to prevent email spoofing.
  • user_scoped_resource_token is computed per the formula above. When using the resource_id and user_scoped_resource_token, the id and token values get ignored.

Legacy fields that you can safely ignore are:

  • id and token are used only for the v1 salted token. Ignore if you’re 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 SHA256 hash you compute doesn’t match the one passed in user_scoped_resource_token, or the SHA1 hash you compute doesn’t match the one passed in resource_token, show the user a page with an HTTP status code of 403. If the timestamp is older than five minutes, they also see a 403.

HTTP status code 403 indicates that the user isn’t 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 SHA256 or SHA1 hashes match, the user is authorized to access the resource in question.

Create a user session through whatever method you normally use, possibly setting a cookie. The session must store that it’s a Heroku single sign-on, because what’s displayed is slightly different for Heroku customers than users logging in through your regular standalone service. Because user access can change at any time, only trust this SSO data 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 context for the user. These parameters include:

  • user: the email address of the current user.
  • app: the Heroku app name the user came from.

Use these parameters 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 using the recommended user_scoped_resource_token:

post "/heroku/sso" do
  pre_user_token = params[:resource_id] + ':' + HEROKU_SSO_SALT + ':' + params[:timestamp] + ':' + params[:user_uuid]  + ':' + params[:email]
  user_token = OpenSSL::HMAC.hexdigest("SHA256", HEROKU_SSO_SALT, (pre_user_token).to_s)
  halt 403 if user_token != params[:user_scoped_resource_token]
  halt 403 if params[:timestamp].to_i < (Time.now - 2*60).to_i

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

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

Here’s a sample implementation using the older resource_token:

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

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

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

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

Additional Reading

  • Implementing Roles for Heroku Users in Add-on SSO Dashboards
  • Create an Add-on “user access list”

Feedback

Log in to submit feedback.

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
  • © 2026 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