Skip to main content

SSO Features

SSO Integration with Forma Cloud

1. What is Forma Cloud SSO?

The FormaLMS SSO system allows the generation of automatic login links that authenticate the user securely through a temporary cryptographic token. This is a common solution for:

  • Automatic redirect from a web application

  • SSO login links in HTML pages

  • API endpoint returning an SSO URL

This guide explains how to correctly implement Single Sign-On (SSO) authentication with FormaLMS, allowing users to access the platform directly from external systems without entering their credentials.


2. How SSO Works

The SSO login process is based on three elements:

  1. login_user – The username of the user who must be authenticated

  2. time – A Unix timestamp representing when the link was generated

  3. token – An MD5 hash that validates the authenticity of the request

The token is calculated using the username, timestamp, and a shared secret key (SSO Secret).


3. SSO URL Structure

A valid SSO URL follows this structure:

https://PLATFORM/index.php?r=adm/homepage/sso&login_user=USERNAME&time=TIMESTAMP&token=TOKEN

Parameters

  • r=adm/homepage/sso – FormaLMS SSO endpoint

  • login_user – User’s username (URL-encoded)

  • time – Current Unix timestamp

  • token – Uppercase MD5 hash

Example

https://forma.example.com/index.php?r=adm/homepage/sso&login_user=mario.rossi&time=1729681425&token=A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6

4. Generating the SSO Token

Step 1: Generate the Unix Timestamp

The Unix timestamp represents the number of seconds elapsed since Jan 1st, 1970 (UTC).

Examples:

  • PHP: time()

  • Node.js: Math.floor(Date.now() / 1000)

  • Python: int(time.time())

  • C# (.NET): DateTimeOffset.UtcNow.ToUnixTimeSeconds()

  • Java: System.currentTimeMillis() / 1000

Important: The timestamp must be generated dynamically at the moment of the SSO request.


Step 2: Calculate the Token

The token is an uppercase MD5 hash of a specific concatenated string:

token = MD5_UPPERCASE(login_user + "," + time + "," + sso_secret)

Where:

  • login_user = the username

  • time = timestamp from Step 1

  • sso_secret = secret key configured in FormaLMS

Example (PHP)

$loginUser = "mario.rossi";
$time = 1729681425;
$ssoSecret = "mia_chiave_segreta_123";
// Build the string
$stringToHash = $loginUser . ',' . $time . ',' . $ssoSecret;
// Result: "mario.rossi,1729681425,mia_chiave_segreta_123"
// Calculate MD5 and convert to UPPERCASE
$token = strtoupper(md5($stringToHash));
// result: "A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6"

 Requirements:
- Commas must match exactly
- No extra spaces
- Final hash must be uppercase


Step 3: Build the Final URL

Once the timestamp and token are ready, construct the final SSO URL:

Example (PHP):

$platformUrl = "https://forma.example.com";

$ssoUrl = $platformUrl . "/index.php"
    . "?r=adm/homepage/sso"
    . "&login_user=" . urlencode($loginUser)
    . "&time=" . $time
    . "&token=" . $token;

5. Full Implementations

The guide includes full sample implementations in:

    PHP

    JavaScript (Node.js)

    Python

    C# (.NET)



    6. Configuration in FormaLMS

    Before using SSO, configure the secret key inside FormaLMS:

    1. Log in as admin

    2. Navigate to Administration → Configuration → SSO

    3. Enter the SSO Secret Key (must match the one used in your code)

    4. Save settings


    Characteristics:

    • Typical validity: 5–10 minutes

    • The link must be used immediately

    • Past or future timestamps are not accepted

    • Expired links require regeneration

    Best practices:


    8.7. Implementation Checklist

    Configuration

    • Secret key configured in FormaLMS

    • Secret matches the one used in external system

    • HTTPS enabled

    Token Generation

    • Timestamp is a Unix timestamp

    • Timestamp generated per request

    • String format: username,time,secret (commas required)

    • MD5 hash converted to uppercase

    • No extra spaces

    URL

    • r=adm/homepage/sso is present

    • Username is URL-encoded

    • All required parameters included


    9.8. Testing and Verification

    Manual Token Test

    Verify the token by hashing a test string in the exact format:

    username,timestamp,secret
    

    Use any MD5 generator to confirm the result.

    Access Test

    1. Generate a valid SSO URL

    2. Open it in a browser within 5 minutes

    3. Confirm the user is logged in

    4. Confirm redirection to the homepage


    10.9. Troubleshooting

    "Invalid token" or "Access denied"

    Check:

    • Matching SSO secret

    • Uppercase MD5 token

    • Correct format (username,timestamp,secret)

    • Existing username in FormaLMS

    Check:

    Redirects to login page

    Check:

    • Correct endpoint (adm/homepage/sso)

    • Username properly URL-encoded

    • All parameters present


    11.10. Security

    Protecting the SSO Secret

    • Keep the secret strictly confidential

    • Never store it in logs, public repos, or client-side code

    • Use environment variables or secret-management systems

    • Rotate the key every 6–12 months

    • Always use HTTPS

    • Do not send SSO URLs through insecure channels

    • Avoid logging full SSO URLs

    • Implement rate limiting

    Monitoring

    • Monitor failed SSO attempts

    • Implement alerts for suspicious activity

    • Periodically audit SSO access logs


    12.11. SSO Variants

    FormaLMS supports two SSO endpoints:

    1. Standard SSO (username-based)

    ?r=adm/homepage/sso&login_user=USERNAME&time=TIME&token=TOKEN
    

    Token: MD5(username,time,secret)

    2. Custom SSO (email-based)

    ?r=adm/ssologin/show&email=EMAIL&time=TIME&token=TOKEN
    

    Token: MD5(email,time,secret)

    Check which one your installation uses.

     

    12. Full Implementation examples

    PHP

    <?php
    
    /**
     * Generates a valid SSO URL for FormaLMS
     *
     * @param string $loginUser   The username of the user
     * @param string $ssoSecret   Secret key configured in FormaLMS
     * @param string $platformUrl Base platform URL
     * @return array              Generated SSO data
     */
    function generateSSOUrl($loginUser, $ssoSecret, $platformUrl)
    {
        // STEP 1: Generate current Unix timestamp
        $time = time();
    
        // STEP 2: Calculate the token
        $stringToHash = $loginUser . ',' . $time . ',' . $ssoSecret;
        $token = strtoupper(md5($stringToHash));
    
        // STEP 3: Build the URL
        $url = rtrim($platformUrl, '/') . "/index.php"
             . "?r=adm/homepage/sso"
             . "&login_user=" . urlencode($loginUser)
             . "&time=" . $time
             . "&token=" . $token;
    
        return [
            'url' => $url,
            'login_user' => $loginUser,
            'time' => $time,
            'token' => $token,
            'valid_until' => date('Y-m-d H:i:s', $time + 300)
        ];
    }
    
    // Example usage
    $ssoData = generateSSOUrl(
        'mario.rossi',                    // Username
        'my_secret_key_123',              // SSO Secret
        'https://forma.example.com'       // Platform URL
    );
    
    echo "SSO URL: " . $ssoData['url'] . "\n";
    echo "Valid until: " . $ssoData['valid_until'] . "\n";
    ?>
    

     

    JavaScript (Node.js)

    const crypto = require('crypto');
    
    /**
     * Generates a valid SSO URL for FormaLMS
     */
    function generateSSOUrl(loginUser, ssoSecret, platformUrl) {
    
        // STEP 1: Unix timestamp
        const time = Math.floor(Date.now() / 1000);
    
        // STEP 2: Calculate token
        const stringToHash = `${loginUser},${time},${ssoSecret}`;
        const token = crypto
            .createHash('md5')
            .update(stringToHash)
            .digest('hex')
            .toUpperCase();
    
        // STEP 3: Build URL
        const baseUrl = platformUrl.replace(/\/$/, '');
        const url = `${baseUrl}/index.php?r=adm/homepage/sso`
                  + `&login_user=${encodeURIComponent(loginUser)}`
                  + `&time=${time}`
                  + `&token=${token}`;
    
        return {
            url: url,
            login_user: loginUser,
            time: time,
            token: token
        };
    }
    
    // Example usage
    const ssoData = generateSSOUrl(
        'mario.rossi',
        'my_secret_key_123',
        'https://forma.example.com'
    );
    
    console.log('SSO URL:', ssoData.url);
    console.log('Token:', ssoData.token);
    

     

    Python

    import hashlib
    import time
    from urllib.parse import quote
    
    def generate_sso_url(login_user, sso_secret, platform_url):
        """
        Generates a valid SSO URL for FormaLMS
        """
    
        # STEP 1: Unix timestamp
        current_time = int(time.time())
    
        # STEP 2: Calculate token
        string_to_hash = f"{login_user},{current_time},{sso_secret}"
        token = hashlib.md5(string_to_hash.encode()).hexdigest().upper()
    
        # STEP 3: Build URL
        base_url = platform_url.rstrip('/')
        url = (f"{base_url}/index.php?r=adm/homepage/sso"
               f"&login_user={quote(login_user)}"
               f"&time={current_time}"
               f"&token={token}")
    
        return {
            'url': url,
            'login_user': login_user,
            'time': current_time,
            'token': token
        }
    
    # Example usage
    sso_data = generate_sso_url(
        'mario.rossi',
        'my_secret_key_123',
        'https://forma.example.com'
    )
    
    print('SSO URL:', sso_data['url'])
    print('Token:', sso_data['token'])
    

     

    C# (.NET)

    using System;
    using System.Security.Cryptography;
    using System.Text;
    using System.Web;
    
    public class FormaSSO
    {
        public static string GenerateSSOUrl(string loginUser, string ssoSecret, string platformUrl)
        {
            // STEP 1: Unix timestamp
            long time = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
    
            // STEP 2: Calculate token
            string stringToHash = $"{loginUser},{time},{ssoSecret}";
            using (MD5 md5 = MD5.Create())
            {
                byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(stringToHash));
                string token = BitConverter.ToString(hashBytes).Replace("-", "").ToUpper();
    
                // STEP 3: Build URL
                string baseUrl = platformUrl.TrimEnd('/');
                string url = $"{baseUrl}/index.php?r=adm/homepage/sso"
                            + $"&login_user={HttpUtility.UrlEncode(loginUser)}"
                            + $"&time={time}"
                            + $"&token={token}";
    
                return url;
            }
        }
    }
    
    // Example usage
    string ssoUrl = FormaSSO.GenerateSSOUrl(
        "mario.rossi",
        "my_secret_key_123",
        "https://forma.example.com"
    );
    
    Console.WriteLine($"SSO URL: {ssoUrl}");