Implementing Single Sign-On

An administrator can implement Single Sign-On to allow users to log in once to access to multiple applications rather than logging in to the individual applications. Single Sign-On can be enabled using SAML 2 or the Custom option.

SAML 2 is a secure Single Sign-On technology that integrates with popular identity management services like Okta and OneLogin.

Instructions on using SAML 2 or the Custom option follow.

Note that Restriction settings only display when you have the Custom Domain feature enabled.

Enabling Single Sign-on in Klipfolio using SAML 2

To use Single Sign-on, administrators must enable it in Klipfolio.

  1. Located at the top right of the screen, click Account.
  2. Select the Settings tab.
  3. Click the Single Sign-On link.
  4. Click the Edit link.
  5. At Single Sign-On (SSO), select SAML 2 to allow users to sign in with the single sign-on.  
  6. Paste in the certificate information you received from your identity management service in the Certificate field.  NOTE: The endpoint is: 
    https://app.klipfolio.com/SAML/consume
  7. Click Save.
  8. Log in to your Identity Management service.


Enabling Single Sign-on in Klipfolio using Custom

Implementing Single Sign-On using the Custom option includes the following tasks:

  1. Enable Single Sign-on for users in Klipfolio.
  2. Create and encrypt a JSON string that contains the user's information. Information on creating a JSON string is provided in this article. 
  3. Enable Single Sign-on using the POST method.
  4. OR, Enable Single Sign-On using the GET method. 

Administrators must enable SSO in Klipfolio. To enable SSO in Klipfolio:

  1. Located at the top right of the screen, click Account.
  2. Select the Settings tab.
  3. Click the Single Sign-On link.
  4. Click the Edit link.
  5. At Single Sign-On (SSO), select Custom to allow users to sign in with the single sign-on.  
  6. Click the Generate New Secret Key link.
  7. Click the Save button.

Customer guidelines for the Custom Single Sign-On option

The following topics are provided as guidelines for customers creating a Single Sign-On token for Klipfolio and includes a sample of specific implementations based on different languages or platforms.

You can use single sign-on to provide users with direct access to Klipfolio from inside a trusted application, such as your company’s intranet, without prompting a user to log in again.

For users accessing Klipfolio with a modern web browser, such as the latest version of Google Chrome or Mozilla Firefox or Microsoft Internet Explorer 10, it is suggested that you use the POST method to implement Single Sign-On.

For users accessing Klipfolio with an older web browser, such as Microsoft Internet Explorer 9, that does not support cross-origin resource sharing (CORS) requests, it is suggested that you use the GET method to implement Single Sign-On.

You must provide Klipfolio with a JSON string that describes the user who is trying to authenticate. The string must be encrypted using AES encryption. The JSON string must include an email address that uniquely identifies the user or an external_id that is assigned to the user by the API.

The following table lists the JSON string attributes.

Name

Description

email Email address.
expires Token expiry date, specified in Unix time format.
external_id Optional: Associated id. If specified, is used as the primary lookup for the user.
logout_url Optional: Redirection location after logging out.
Note You must select either an email address or external_id.

 

Encrypting the JSON string

Use the following guidelines to encrypt the JSON string.

    1. Start with a JSON string.
    2. Generate the secret key using the Klipfolio administration tools located in the Klipfolio account settings.

Important: A secret key can be regenerated at any time. However, this action invalids any existing tokens and requires an update to the encryption code.

  1. Use the secret key and company id as part of the salt.
  2. Encrypt using AES/CBC/PKCS5Padding.
  3. Prepend the initialization vector to the encrypted token.
  4. Encode with ciphertext Base64.

Tip: You can validate the generated Single Sign-on token for any error messages at the Klipfolio SSO Test Page.

Enable Single Sign-on using the POST method

You must post the encrypted token to the authentication endpoint.

    1. POST the token to the /users/sso_auth directory.

Note: The POST must contain the Single Sign-on token and the ID of the company making the request.

The token can either be sent in:

      • the request header 'KF-SSO'
      • the request query string parameter 'sso' (url-encoded)

The company ID can either be sent in:

      • the request header 'KF-Company'
      • the request query string parameter 'company'

 

  1. Optional: To end a user's session, you can also POST the token to the /users/sso_logout directory.

Enable Single Sign-On using the GET method

You can use GET requests to implement single sign-on between a trusted application and Klipfolio. This parameter automatically redirects a user to the Dashboard after successful authentication.

The parameter is &redirect=true

It is suggested you use this method for users accessing Klipfolio with Microsoft Internet Explorer 9 which does not support CORS requests or Microsoft Internet Explorer 10 configured with restricted security settings.

The following information is provided as a guideline to implementing the GET method of single sign-on.

 

  • GET the token: /users/sso_auth.

 

Note: The GET request must contain the Single Sign-on token and the ID of the company making the request.

The token can either be sent in:

  • the request header 'KF-SSO'
  • the request query string parameter 'sso' (url-encoded)

The company ID can either be sent in:

  • the request header 'KF-Company'
  • the request query string parameter 'company'

 

  • Optional: To end a user's session, you can also POST the token to the /users/sso_logout directory.

 

Error handling

The JSON response can help you troubleshoot problems related to Single Sign-on. A successful request provides information about the authorized user. An unsuccessful request provides one of the following error codes.

Code

Error

Description

1 no_sso_support Single-sign-on is not enabled.  Enable SSO in Account > Settings > Single-Sign-On.
2 token_expired The current time is greater than the token’s specified ‘expires’ time.
3 token_parse Unable to parse the token as a JSON object.
4 no_user_found Unable to find a user for a given email address or external_id.
5 user_does_not_belong_to_company The resolved user does not belong to the company making the request.
6 decryption Unable to decrypt the token. Ensure that the token is encrypted/transported to specification.
7 no_token_param The request does not contain the SSO token in either the request header or query string.
8 no_company_param The request does not contain the company-id in either the request header or query string.
9 no_company Unable to find the company for the given id.
10 expires_date_parse Unable to parse the ‘expires’ field. Specify the date in Unix time format.

Code samples

The following blocks of code are provided as examples.

Example of a user token that is identified by email:

{

    email : "user@acme.com",

    expires: "1377272230"

}

 

 

Example of a user token that is identified by customer ID:

 

{

    external_id : "123456",

    expires: "1377272230"

}

 

Language code snippets

Click the following links to download code snippets for most major languages.

https://static.klipfolio.com/images/saas/sso_ruby.txt 
https://static.klipfolio.com/images/saas/sso_py.txt 
https://static.klipfolio.com/images/saas/sso_php.txt 
https://static.klipfolio.com/images/saas/sso_pl.txt 
https://static.klipfolio.com/images/saas/sso_cs.txt

Example Code: Java

 

import org.apache.commons.codec.binary.Base64;

import org.apache.commons.codec.digest.DigestUtils;

import org.apache.commons.codec.net.URLCodec;

import org.json.JSONObject;

 

import javax.crypto.Cipher;

import javax.crypto.CipherOutputStream;

import javax.crypto.spec.SecretKeySpec;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.InputStream;

import java.io.OutputStream;

 

public class KFTokenGeneratorExample

{

    private SecretKeySpec secretKeySpec;

    private Base64 base64 = new Base64();



    public KFTokenGeneratorExample(String klipfolioCompanyId, String ssoKey)

    {

        String salted = ssoKey + klipfolioCompanyId;

        byte[] hash = DigestUtils.sha(salted);

        byte[] saltedHash = new byte[16];

        System.arraycopy(hash, 0, saltedHash, 0, 16);

 

        secretKeySpec = new SecretKeySpec(saltedHash, "AES");

    }



    private void encrypt(InputStream in, OutputStream out) throws Exception

    {

        try

        {

            byte[] buf = new byte[1024];

 

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);

 

            out.write(cipher.getIV());

 

            CipherOutputStream cipherOutputStream

= new CipherOutputStream(out, cipher);

 

            int numRead = 0;

            while ((numRead = in.read(buf)) >= 0)

            {

                cipherOutputStream.write(buf, 0, numRead);

            }

            cipherOutputStream.close();

 

        }

        catch (Exception e)

        {

            e.printStackTrace();

        }

 

    }



    public String create(JSONObject json) throws Exception

    {

        byte[] data = json.toString().getBytes("UTF-8");

        ByteArrayOutputStream out = new ByteArrayOutputStream();

        encrypt(new ByteArrayInputStream(data), out);

 

        return new String(base64.encode(out.toByteArray()));

    }

 

    public static void main(String[] args)

    {

        try

        {

// go to: https://app.klipfolio.com/settings/single_signon_edit
// to find your companyId and secretKey
// --------------------------------------------------------------

String companyId = "<company-id>";
String secretKey = "<secret-key>";
String email = "<klipfolio-login-email>";

 

JSONObject jsonObj = new JSONObject();

jsonObj.put("email", email);

 

 

            KFTokenGeneratorExample tokenGenerator = new KFTokenGeneratorExample(companyId,secretKey);

 

            String token = tokenGenerator.create(jsonObj);

 

System.out.println("Test this token: http://jsfiddle.net/mpriatel/7Dxg5/\n\n" +
"email = " + email + "\n" +
"token = " + token + "\n" +
"company id = " + companyId
);

 

        }

        catch (Exception e)

        {

            e.printStackTrace();

        }

    }

}

 

 

Example Transport Code: JavaScript

The following example uses jQuery to POST the Single Sign-on token to Klipfolio.

In this example, to create a token for a specific user, the value of encrypted token is generated on the server first, and then passed to the user interface.

function initKlipfolioSSO( onSuccess, onError ){

    $.ajax({

 

        url : "https://app.klipfolio.com/users/sso_auth",

        type: "post",

        xhrFields:{

            withCredentials:true

        },

        headers:{

        "KF-SSO":"<encrypted token>",

            "KF-Company":"<company id>"

        },

        dataType:"json",

       

// on success, the data object will contain information about

        // the authenticated user

        // ----------------------------------------------------------

        success : function(data){

            console.log(data);
                    onSuccess(data);

        },

 

        // on error, err.responseJSON will contain an error code

        // -----------------------------------------------------

        error : function(err){

            console.log("sso auth failed",err.responseJSON);

                    onError(data);

        }

})

}

After the POST is completed, the user is provided with an authenticated session to Klipfolio. As a best practice, only request a session when a user intends to interact with their dashboard.

 

// create an SSO session on page-load.

// ------------------------------------------------

$( initKlipfolioSSO() );

 

 

 

For example, the above code is not recommended as it sends a session request for every page load and will return invalid usage data. Instead, it is preferable to only create the Single Sign-on session on demand as shown below.

// only request an SSO session when the user wants to view their dashboard

// ---------------------------------------------------------------------------

 

$("#dashboard-link").click( function( ){

    initKlipfolioSSO(

        function(data){

            document.location = "https://app.klipfolio.com/dashboard"

        },

        function(data){

            alert("Dashboard is temporarily unavailable.");

        },

);


})

 

 

 

 

 
 

Related Links