New Check out Muut IO for developers
Muut Blog

Implementing Muut Fed-Id (SSO) in PHP

Courtney Couch • 2016-01-27

Our Federated identities feature allows you to transparently create and authorize users using identities you control. This allows you to create a truly seamless user experience.. Users register on your site, browse to your forum, and post. No need to register for another service. No need to remember yet another password. Completely frictionless. When you couple that with the fact that Muut can be blended into your existing site, there’s nothing that comes close to what you can accomplish with Muut.

We’re going to implement a complete Fed-ID instance of Muut on PHP in this article. If you are on Wordpress, our Wordpress plugin has this functionality built in so install that plugin and you are ready to go. If you are on Shopify, our Shopify plugin has the same functionality. Install that plugin to accomplish the same.

What you need

Ability to execute code

First of all, to implement this you’ll need access to generate the embeds from the server-side. This means if you are on something like Squarespace, then you are currently out of luck until they give some sort of API or access for us to integrate into.

A user database and authentication mechanism

If you intend on authenticating users on Muut using Federated Identities you need to have some way to determine who they are, and control those identities on your end. You can’t very well tell Muut who the users are if you don’t know who they are.

Some coding experience

We’ve tried to make this as simple as possible, but since you must be generating the embed from the server there’s no getting around it. You need at least some knowledge here.

What we’re going to build

We’re going to create a registration form that lets users enter a username and an email address. After submitting that form, if they visit a page with a Muut forum or Muut private messaging, they will automatically be authenticated as that user. We will also use Gravatar to make a user icon for them defaulting to our logo for our fake company.

Let’s get started

First we’re going to put together the basic non-Muut pieces. We’re going to setup a page that has a basic form. Users can get past the page once they enter an email address and username.

We’re not going to use any framework or database for this so we can keep this example as simple as possible.

Here’s a basic login form we can add save as login.php

<html>
<body>

<form method="POST">

<input type="text" name="username" placeholder="username"/><br/>
<br/>
<input type="submit" value="login"/>
</form>

</body>
</html>

This form doesn’t do anything yet, so let’s add some PHP at the top to take whatever username and email they enter and do something with it.

Stick this at the top of the same file:

<?php
//creates or resumes a session to track login state
session_start();

//form is submit
if ($_SERVER["REQUEST_METHOD"] == "POST") {

  //let’s make sure the values are entered
  //obviously in a real app you should validate the data as well
  if (!empty($_POST["username"])) {

   //We’re going to make a user object and use the username
   //as the unique id as well as what we display
   $_SESSION['user'] = array(
    "id" => $_POST["username"],
    "displayname" => $_POST["username"]
    );

  }
}
?>

This doesn’t actually do anything after you submit the form, so you can’t see what’s happening. The above checks to make sure the request method is “POST” (so we know the form was submitted) and verifies that the field is entered. Then we setup the session so that, once submitted, they are assigned as that same user.

Now, let’s redirect that user to another page when they “login/register”.

Add this line: header( 'Location: ./index.php' ) ; after saving the user object to the session so you have this for login.php:

<?php
//creates or resumes a session to track login state
session_start();

//form is submit
if ($_SERVER["REQUEST_METHOD"] == "POST") {

  //let’s make sure the values are entered
  //obviously in a real app you should validate the data as well
  if (!empty($_POST["username"])) {

   //We’re going to make a user object and use the username
   //as the unique id as well as what we display
   $_SESSION['user'] = array(
    "id" => $_POST["username"],
    "displayname" => $_POST["username"]
    );
   header( 'Location: ./index.php' ) ;

  }
}
?>
<!DOCTYPE html>
<html>
<head>

<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="viewport" content="width=device-width">

</head>
<body>

<form method="POST">

<input type="text" name="username" placeholder="username"/><br/>
<br/>
<input type="submit" value="login"/>
</form>

</body>
</html>

Now when you submit this you will see an error that there is no index.php page. Let’s add something here:

<?php
session_start();

?>
<!DOCTYPE html>
<html>
<head>

<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="viewport" content="width=device-width">

</head>
<body>
<?php if ($_SESSION['user']) { ?>
  <a href="./logout.php"> logout </a>
<?php } else { ?>
  <a href="./login.php"> login </a>
<?php } ?><br/><br/>

<hr>
</body>
</html>

Now we’ve got an index page that will show a logout link if they have logged in — if they aren’t, it will show a login link that links to our fake little login form.

Let’s quickly make the logout.php page we linked to

<?php
session_start();

unset($_SESSION['user']);

header( 'Location: ./index.php' ) ;

This is pretty basic. We resume the session, delete the user property from the session and send them back to the index.php page.

So now with all 3 of these pages together you can click around, login, logout and so on. Of course, in a real application you’d be doing validation, storing the user, saving and verifying passwords, and so on.

Adding Muut

Now that we have the basics we’ll add Muut into the mix.

We’re going to go back to the index.php file and add more to the top of it:

//the api key from your forum settings
$public_key = "apikey";
// the secret key from your forum settings
$private_key = "testapisecretkey";

//saving the user object from the session into
//a new “auth” object
$auth_object = array( "user" => $_SESSION['user'] );

//Taking the auth object, converting to json then
//base64 encoding the json data
$message  = base64_encode(json_encode($auth_object));

//save the current server timestamp
$timestamp  = time();

//we’re creating a signature using the message, timestamp,
//and secret key
$signature  = sha1($private_key . ' ' . $message . ' ' . $timestamp);

First we’ll store the private and public API key from your forum. You can get your API keys here.

Then we’ll take that “user” structure we created from the login page and save it to a new structure. We only do this because we might be storing other data in the session that we don’t want to pass along to the user. Anything in this auth_object will be sent to the browser so we wouldn’t want to just send the entire session.

Now that we have the auth_object we need to encode it in a way that Muut can understand. We first convert it to JSON, then we take that JSON string and convert it to base64. This is now saved as the property $message.

Then it’s just a matter of getting a timestamp and signature.

What is the signature for?

When using Fed-ID, you control user authentication and tell Muut who is whom. Without a signature someone could take the html on your site then change their user id — Muut would then think they are a completely different user. Users could even become an admin by modifying the message string. This is, obviously, bad. You don’t want users being able to impersonate admins and other users, so we have to somehow verify a user is truly whomever the Muut embed claims.

This is where the signature comes in. We use the final message combined with the private key to generate a hash. Hashes are one way cryptographic functions so the Muut servers can verify that the message string hasn’t been tampered with. The timestamp is used in generating the signature so we can verify the timestamp hasn’t been tampered with — and so that a user can’t save a signature and reuse it some other time. The server can verify “yes this timestamp is from the last x minutes” and “yes this signature passed matches so I know the message string and timestamp haven’t been tampered with”.

Now that we have the authentication variables, let’s add the Muut embed itself to the index.php page.

Add this to the html portion under the hr tag:

<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<link rel="stylesheet" href="//cdn.muut.com/1/moot.css">
<script src="//cdn.muut.com/1/moot.min.js"></script>
<a id="my-community" href="https://muut.com/i/playground">Community</a>

<script>
$('#my-community').muut({
  api: {
    key: '<?php echo $public_key ?>',
    message: '<?php echo $message ?>',
    signature: '<?php echo $signature ?>',
    timestamp: <?php echo $timestamp ?>
  }
})
</script>

First we’ll add jQuery (Muut needs it), then we add the Muut CSS and JS. Normally the Muut client handles the extra includes automatically but with Fed-ID we’ve got to add these manually.

Once added, we can replace the community link with your own. In this case we’re using the Muut test playground community. To do this, you’d replace “playground” with your own community name (eg. https://muut.com/i/mycommunityname).

Next: $('#my-community') is jQuery code to select the HTML element with the id “my-community”. With that, we call muut() to initialize it as a Muut community.

The muut() initialization script supports configuration objects we need, and the api configuration object is where the Fed-ID magic happens. It’s here that we’ll add all the fields we created earlier: message, timestamp, and signature. We’ll also pass along the public api key.

Save the file and run it!

You have now officially created a working basic Fed-ID implementation. Your final index.php file should look like this:

<?php
session_start();

//the api key from your forum settings
$public_key = "apikey";
// the secret key from your forum settings
$private_key = "testapisecretkey";

//saving the user object from the session into
//a new “auth” object
$auth_object = array( "user" => $_SESSION['user'] );

//Taking the auth object, converting to json then
//base64 encoding the json data
$message  = base64_encode(json_encode($auth_object));

//save the current server timestamp
$timestamp  = time();

//we’re creating a signature using the message, timestamp,
//and secret key
$signature  = sha1($private_key . ' ' . $message . ' ' . $timestamp);


?>
<!DOCTYPE html>
<html>
<head>

<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="viewport" content="width=device-width">

</head>
<body>
<?php if ($_SESSION['user']) { ?>
  <a href="./logout.php"> logout </a>
<?php } else { ?>
  <a href="./login.php"> login </a>
<?php } ?><br/><br/>

<hr>

<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<link rel="stylesheet" href="//cdn.muut.com/1/moot.css">
<script src="//cdn.muut.com/1/moot.min.js"></script>
<a id="my-community" href="https://muut.com/i/playground">Community</a>

<script>
$('#my-community').muut({
  api: {
    key: '<?php echo $public_key ?>',
    message: '<?php echo $message ?>',
    signature: '<?php echo $signature ?>',
    timestamp: <?php echo $timestamp ?>
  }
})
</script>

</body>
</html>

When the session does not have a user object in it, Muut will show them as logged out. If you create a new user, Muut recognizes this and the user is created behind the scenes. You can login and logout as different users and you’ll never have to register with Muut. It’s almost magical.

Muut Messaging

Now that we have the forum in place, let’s add Muut Messaging on a standalone contact page. Perhaps a button for people to send a private message.

It will look almost identical to the index.php page. Save this as contact.php:

<?php
session_start();

//the api key from your forum settings
$public_key = "apikey";
// the secret key from your forum settings
$private_key = "testapisecretkey";

//saving the user object from the session into
//a new “auth” object
$auth_object = array( "user" => $_SESSION['user'] );

//Taking the auth object, converting to json then
//base64 encoding the json data
$message  = base64_encode(json_encode($auth_object));

//save the current server timestamp
$timestamp  = time();

//we’re creating a signature using the message, timestamp,
//and secret key
$signature  = sha1($private_key . ' ' . $message . ' ' . $timestamp);


?>
<!DOCTYPE html>
<html>
<head>

<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="viewport" content="width=device-width">

</head>
<body>
<?php if ($_SESSION['user']) { ?>
  <a href="./logout.php"> logout </a>
<?php } else { ?>
  <a href="./login.php"> login </a>
<?php } ?>
  | <a href="./index.php">Forum</a>
<br/><br/>

<hr>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<link rel="stylesheet" href="//cdn.muut.com/1/moot.css">
<script src="//cdn.muut.com/1/moot.min.js"></script>

<!-- We're adding this cs/js in addition to the others -->
<link rel="stylesheet" href="//cdn.muut.com/1/muut-messaging.css">
<script src="//cdn.muut.com/1/muut-messaging.min.js"></script>

<!-- this is a basic messaging button -->
<button class="muut-messaging-button" data-recipients="Message Courtney <courtneycouch>" data-forumname="playground">Message Courtney</button>

<!-- This becomes the messaging button on the bottom-right -->
<span class="muut-messaging">Messages</span>

<script>
  muut.messaging({
    url: 'playground',
    api: {
      key: '<?php echo $public_key ?>',
      message: '<?php echo $message ?>',
      signature: '<?php echo $signature ?>',
      timestamp: <?php echo $timestamp ?>
    }
  });
</script>

</body>
</html>

If you look at the above it’s mostly the same with a few small changes. First we added another JS and CSS file. These files are messaging related. Then we added a message button with a recipient prefilled. Details about this are here.

Then we add in the span tag which will become the messages link.

Finally we use the JavaScript initialization as you see mentioned on our advanced embedding docs here with a small change. Instead of a string for the community name, we passed in an object. This object has a property url for the name of the community and the same api object we used on the index.php page.

We also added a small link to go back to the index.php page. We should add a similar link to the index.php page: | <a href="./contact.php">Messaging</a> in the same place.

Polishing

Now that we’ve got a rough login/logout Fed-ID implementation for a Muut forum and Muut messaging let’s clean it up a bit.

First up, we’ll make the user a bit more complete. We’ll add an avatar and capture an email address that we pass to Muut. Passing an email to Muut isn’t necessary, but we can’t email them about new messages or replies to their threads without it.

So, to do this we’ll go back to the login.php page, where we’ll capture an email address and add it to the user object.

Add this to the form: <input type="text" name="email" placeholder="email address"/><br/> under the username field.

Then change the php part at the top to this:

if ($_SERVER["REQUEST_METHOD"] == "POST") {
  if (!empty($_POST["username"]) && !empty($_POST["email"])) {
    $_SESSION['user'] = array(
    "id" => $_POST["username"],
    "displayname" => $_POST["username”],
    “email” => $_POST[“email”]
    );
  }
}

We’re adding the email property to the user object and verifying that an email is provided. Of course, in a real app you will be verifying this value.

Now Muut will be able to email users for new events. Next, we’ll add an avatar, starting with adding a function to generate the avatar location:

function get_avatar($email) {
  return "https://secure.gravatar.com/avatar/" . md5( strtolower( trim( $email ) ) ) . "?s=120";
}

This function will take an email address and generate a Gravatar url from it that is 120 pixels across. We also used https so that the avatars will load even if your site is loaded securely.

If people don’t have Gravatar avatars setup we’ll end up with a generic G icon. Instead, let’s use our logo as the default if the user doesn’t have something created. To do that we’ll change the function to:

function get_avatar($email) {
  $default_avatar = "https://muut.com/home/img/muut.png";
  return "https://secure.gravatar.com/avatar/" . md5( strtolower( trim( $email ) ) ) . "?d=" . urlencode( $default_avatar ) . "&s=120";
}

We’ll use https://muut.com/home/img/muut.png as the default if they don’t have an avatar.

Now we’ll update the original session creation:

$_SESSION['user'] = array(
    "id" => $_POST["username"],
    "displayname" => $_POST["username”],
    “email” => $_POST[“email”],
    “avatar” => get_avatar($_POST[“email”])
    );

That’s all there is to it. Now, when any user logs in Muut will update the database to reflect the avatar identified above.

Next, we should update it so that Muut knows where our login page is. Muut will then link the input boxes to that page and add a login link. The messaging option will also direct the user to our login page.

Go back to index.php and change the initialization to this:

$('#my-community').muut({
  login_url: "./login.php",
  api: {
    key: '<?php echo $public_key ?>',
    message: '<?php echo $message ?>',
    signature: '<?php echo $signature ?>',
    timestamp: <?php echo $timestamp ?>
  }
})

Now Muut will direct the user to ./login.php to login. You can use relative or absolute urls here depending on your needs.

We’ll do the same on the contact.php page:

muut.messaging({
    url: 'playground',
    login_url: "./login.php",
    api: {
      key: '<?php echo $public_key ?>',
      message: '<?php echo $message ?>',
      signature: '<?php echo $signature ?>',
      timestamp: <?php echo $timestamp ?>
    }
  });

Now we’re starting to get somewhere. Muut doesn’t feel like an external system anymore. We can load the forum, login, come back, post, we have a nice little avatar and everything works simply with very little work on our end.

tl;dr

You never have to worry about creating users, importing users, or anything of the sort. As long as the “id” field of the user remains the same they will continue to keep their feed and continue to be considered the same user by our system.

We make completely transparent integrations as simple as possible for you so that your users never have to hit friction points when using Muut.

You can see the complete 4 PHP files we created here.

If you run into any typos, ping us.

The complete discussion system for your site

Try all features 14 days without credit card. Ready to upgrade? Check our plans and pricing.