ProdCamp Help
Go to ProdCampSign InLeave Feedback
  • What is ProdCamp?
  • How it works
  • Getting Started
    • Getting Started with ProdCamp
    • Invite Your Team
    • Custom Domain
  • Customer feedback
    • Attaching Feedback to a Feature
    • Processing Feedback
  • Feedback Channels
    • Customer Feedback Channels
    • ProdCamp App
    • Public Roadmap
    • Feature Voting Portal
    • Email Forwarding
    • Google Chrome Extension
    • Intercom Messanger
    • Embeddable Feedback Widget
    • NPS
    • Any App (via Zapier)
  • Installing widgets
    • Installing widgets
    • Widgets SSO
    • Changelog widget
    • Feedback Widget
    • NPS widget
  • Features
    • Creating a Feature
    • Sharing Features on Public Roadmap
    • Push Feature to Jira
    • Feature Releases
    • Features and Sprints relation
  • Feedback Loop
    • Closing Feedback Loop
    • Changelog
  • Roadmaps
    • Public Roadmap
    • Single Sign-On (SSO)
    • Feature Placement on the Public Roadmap
    • Internal Roadmap
    • Protected Roadmap (beta)
  • ❌Sprints (DEPRECATED)
    • Sprints Mode
    • Create Sprint
    • Adding Features to a Sprint
    • Sprint Releases
  • Products
    • Create and Manage Products
  • Prioritization
    • Prioritization Matrix
    • RICE Prioritization
  • Customers
    • Manage Accounts and Contacts
    • Sync Accounts with SalesForce
  • Integrations
    • Slack
    • Jira
    • GitLab
    • SalesForce
    • Intercom
    • Zapier
  • Operations
    • Import Features
    • Import Customers
  • Settings
    • Profile
  • Getting Help
    • Contact Us
  • API
    • Authentication
    • Feedback API
      • Feedback Types
      • Feedback States
    • Features API
    • Customers API
Powered by GitBook
On this page
  • What is Single Sign-On
  • How to generate a token
  • Get required parameters from your ProdCamp account
  • Install library
  • Generate the token
  • How to use the token to authenticate public roadmap users

Was this helpful?

  1. Roadmaps

Single Sign-On (SSO)

PreviousPublic RoadmapNextFeature Placement on the Public Roadmap

Last updated 1 year ago

Was this helpful?

What is Single Sign-On

If you have accounts of your users in your system - you can effectively provide this data using a JSON Web Token generated on your server to authenticate users on your public roadmap. This mechanism is called Single Sign-On.

How to generate a token

Here are the instructions on how to generate and use a token for signing in users automatically on your public roadmap or in your widgets

Get required parameters from your ProdCamp account

  • Login to your ProdCamp account (you must be an account administrator)

  • Go to the Settings page and then to the Workspace tab

  • On the Workspace tab, there are two important things that you will need to generate a token: Workspace Id and Secret key. You will need it a bit later in this article.

Install library

First, you need to install a specific library for working with JWT tokens

npm install --save jsonwebtoken
# Read more here:
https://www.nuget.org/packages/System.IdentityModel.Tokens.Jwt/
# Read more here:
https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt/0.7.0
composer require firebase/php-jwt
sudo gem install jwt
pip install PyJWT
go get github.com/dgrijalva/jwt-go

Generate the token

Copy and insert the Secret key from the Workspace tab to the SecretKey variable in the snippet. Fill in the user data by providing user email, first name, last name, etc., and the Workspace Id. Then encode this data using the secret key like it's shown below:

var jwt = require('jsonwebtoken');

var SecretKey = 'your_secret_key';

function createToken() {
  var userData = {
    avatarUrl: 'user_avatar_url',
    email: 'johndoe@foo.com' // required
    firstName: 'John',
    lastName: 'Doe',
    company: JSON.stringify({
      name: 'Foo Company',
      revenue: 1000
    }),
    workspace_id: '01234567-1c34-1b34-1234-cecb45ab891f' // required
  };
  return jwt.sign(userData, SecretKey, {algorithm: 'HS256'});
}

var token = createToken();
private static string SecretKey = "your_secret_key";

public static string CreateToken()
{
    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecretKey));
    var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
    var tokenHandler = new JwtSecurityTokenHandler();
// edited on Aug 3, 2023
//  const header = new JwtHeader(credentials);
    var header = new JwtHeader(credentials);
  
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(
            new List<Claim>() {
                new Claim("email", "johndoe@foo.com"), // required
                new Claim("avatarUrl", "user_avatar_url"),
                new Claim("firstName", "John"),
                new Claim("lastName", "Doe"),
                new Claim("company", 
                    // Newtonsoft.Json library usage
                    JsonConvert.SerializeObject(new {
                        Name = "Foo Company",
                        Revenue = 1000
                    })
                ),
                new Claim("workspace_id", "01234567-1c34-1b34-1234-cecb45ab891f") // required
            }
        ),
// edited on Aug 3, 2023
//      SigningCredentials = creds
        SigningCredentials = credentials
    };

    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}
import java.util.HashMap;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

public class TokenFactory {
  private static final String SecretKey = "your_secret_key";

  public static String createToken() throws Exception {
    HashMap<String, Object> userData = new HashMap<String, Object>();
    
    // new CompanyDTO(companyName, revenue)
    CompanyDTO companyDto = new CompanyDTO("Foo Company", 1000);
    Gson gson = new Gson();
    String companyJson = gson.toJson(companyDto);

    userData.put("email", "johndoe@foo.com"); 
    userData.put("avatarUrl", "user_avatar_url");
    userData.put("firstName", "John");
    userData.put("lastName", "Doe"); 
    userData.put("company", companyJson);
    userData.put("workspace_id", "01234567-1c34-1b34-1234-cecb45ab891f"); // required
    
    return Jwts.builder()
               .setClaims(userData)
               .signWith(SignatureAlgorithm.HS256, SecretKey.getBytes("UTF-8"))
               .compact();
  }
}
use \Firebase\JWT\JWT;

$SecretKey = 'your_secret_key';

function createToken() {
  $companyData = [
    'name' => 'Foo Company',
    'revenue' => 1000
  ];
  
  $companyDataJson = json_encode($companyData);

  $userData = [
    'email' => 'johndoe@foo.com', // required
    'avatarUrl' => 'user_avatar_url',
    'firstName' => 'John',
    'lastName' => 'Doe',
    'company' => $companyDataJson,
    'workspace_id' => '01234567-1c34-1b34-1234-cecb45ab891f' // required
  ];
  return JWT::encode($userData, $SecretKey, 'HS256');
}
require 'jwt'
require 'json'

SecretKey = 'your_secret_key'

def createToken()
  companyData = {
    name: 'Foo Company',
    revenue: 1000   
  }
  
  userData = {
    email: 'johndoe@foo.com' # required
    avatarUrl: 'user_avatar_url',
    firstName: 'John',
    lastName: 'Doe',
    company: companyData.to_json,
    workspace_id: '01234567-1c34-1b34-1234-cecb45ab891f' # required
  }

  JWT.encode(userData, SecretKey, 'HS256')
end
import jwt
import json

secret_key = 'your_secret_key'

def create_token():
  company_data = {
    'name': 'Foo Company',
    'revenue': 1000
  }
  
  company_json = json.dumps(company_data)
  
  user_data = {
    'avatarUrl': 'user_avatar_url',
    'email': 'johndoe@foo.com' # required
    'firstName': 'John',
    'lastName': 'Doe',
    'company': company_json
    'workspace_id': '01234567-1c34-1b34-1234-cecb45ab891f' # required
  }
  
  return jwt.encode(user_data, secret_key, algorithm='HS256')
import (
  "github.com/dgrijalva/jwt-go"
  "encoding/json"
)

const SecretKey = "your_secret_key"

type CompanyData struct {
  Name  string
  Revenue  int
}

func createToken() (string, error) {
  companyData = CompanyData {
    Name: "Foo Company",
    Revenue: 1000
  }
  
  token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
    "avatarUrl": "user_avatar_url",
    "email": "johndoe@foo.com" // required
    "firstName": "John",
    "lastName": "Doe",
    "company": json.Marshal(companyData),
    "workspace_id": '01234567-1c34-1b34-1234-cecb45ab891f' // required
  })
  return token.SignedString([]byte(SecretKey))
}

How to use the token to authenticate public roadmap users

After that, you can use the generated token inside the query parameter of a public roadmap URL like https://roadmap.prodcamp.com?token={generated_token} and provide this link somewhere inside your app to quickly redirect your users to your public roadmap page where they will be automatically authenticated and will have the ability to leave feedback right away.

You can also use this token to secure your widgets from any unauthorized access. .

Learn more here