diff --git a/docs/index.txt b/docs/index.txt
index 355ed5ede472884f8025196d40043e971302d8bd..3ce5c8de1c534a4fa2b2bd08ac8e0297f4f0c60f 100644
--- a/docs/index.txt
+++ b/docs/index.txt
@@ -35,6 +35,7 @@ SimpleSAMLphp Documentation
  * [Key rollover](./saml:keyrollover)
  * [Creating authentication sources](./simplesamlphp-authsource)
   * [Implementing custom username/password authentication](./simplesamlphp-customauth)
+ * [Storing sessions in Riak](./riak:simplesamlphp-riak)
 
 Documentation on specific simpleSAMLphp modules:
  
diff --git a/modules/riak/config-templates/module_riak.php b/modules/riak/config-templates/module_riak.php
new file mode 100644
index 0000000000000000000000000000000000000000..604bb3c916fef4f2d33e0483152a86194ee28d28
--- /dev/null
+++ b/modules/riak/config-templates/module_riak.php
@@ -0,0 +1,17 @@
+<?php
+/*
+ * The configuration of the riak Store module
+ *
+ * $Id$
+ */
+
+$config = array (
+	/*
+	 * This module has the following config options and defaults.
+	 *
+	 * 'path' => 'riak-php-client/riak.php',
+	 * 'host' => 'localhost',
+	 * 'port' => 8098,
+	 * 'bucket' => 'SimpleSAMLphp',
+	 */
+);
diff --git a/modules/riak/default-disable b/modules/riak/default-disable
new file mode 100644
index 0000000000000000000000000000000000000000..fa0bd82e2df7bd79d57593d35bc53c1f9d3ef71f
--- /dev/null
+++ b/modules/riak/default-disable
@@ -0,0 +1,3 @@
+This file indicates that the default state of this module
+is disabled. To enable, create a file named enable in the
+same directory as this file.
diff --git a/modules/riak/docs/simplesamlphp-riak.txt b/modules/riak/docs/simplesamlphp-riak.txt
new file mode 100644
index 0000000000000000000000000000000000000000..69cf89a90e35bfc36cd9b55fc58b4a471e940486
--- /dev/null
+++ b/modules/riak/docs/simplesamlphp-riak.txt
@@ -0,0 +1,118 @@
+Riak Store module
+=================
+
+<!--
+	This file is written in Markdown syntax.
+	For more information about how to use the Markdown syntax, read here:
+	http://daringfireball.net/projects/markdown/syntax
+-->
+
+  * Version: `$Id$`
+
+<!-- {{TOC}} -->
+
+Introduction
+------------
+
+The riak module implements a Store that can be used as a backend
+for simpleSAMLphp session data like the phpsession, sql, or memcache
+backends.
+
+Preparations
+------------
+
+The obvious first step for using Riak as a backend is to install
+and configure a Riak cluster for SimpleSAMLphp to use. Please refer
+to the Riak documentation for this.
+
+This module requires the use of a Riak backend that supports secondary
+indexes. Refer to the Riak documentation on how to enable an
+appropriate backend for use by this module. Currently the only
+storage backend that supports secondary indexes is leveldb.
+
+Next, you will need to install the Riak PHP Client library, available
+from https://github.com/basho/riak-php-client.
+
+Finally, you need to config SimpleSAMLphp to for the riak Store by
+enabling the following modules:
+
+ 1. cron
+ 2. riak
+
+The cron module allows you to do tasks regularly by setting up a
+cronjob that calls hooks in simpleSAMLphp. This is required by the
+riak module to remove expired entries in the store.
+
+Enabling the riak module allows it to be loaded and used as a storage
+backend.
+
+You also need to copy the `config-templates` files from the cron
+module above into the global `config/` directory.
+
+	$ cd /var/simplesamlphp
+	$ touch modules/cron/enable
+	$ cp modules/cron/config-templates/*.php config/
+	$ touch modules/riak/enable
+	$ cp modules/riak/config-templates/*.php config/
+
+
+Configuring the cron module
+---------------------------
+
+At `/var/simplesamlphp/config`
+
+	$ vi module_cron.php
+
+edit:
+
+	$config = array (
+		'key' => 'secret',
+		'allowed_tags' => array('daily', 'hourly', 'frequent'),
+		'debug_message' => TRUE,
+		'sendemail' => TRUE,
+	);
+
+Then: With your browser go to => https://simplesamlphp_machine/simplesaml/module.php/cron/croninfo.php
+
+And copy the cron's sugestion:
+
+	-------------------------------------------------------------------------------------------------------------------
+	Cron is a way to run things regularly on unix systems.
+
+	Here is a suggestion for a crontab file:
+
+	# Run cron [daily]
+	02 0 * * * curl --silent "https://simplesamlphp_machine/simplesaml/module.php/cron/cron.php?key=secret&tag=daily" > /dev/null 2>&1
+	# Run cron [hourly]
+	01 * * * * curl --silent "https://simplesamlphp_machine/simplesaml/module.php/cron/cron.php?key=secret&tag=hourly" > /dev/null 2>&1
+	# Run cron [frequent]
+	XXXXXXXXXX curl --silent "https://simplesamlphp_machine/simplesaml/module.php/cron/cron.php?key=secret&tag=frequent" > /dev/null 2>&1
+		Click here to run the cron jobs:
+
+	Run cron [daily]
+	Run cron [hourly]
+	Run cron [frequent]
+	-------------------------------------------------------------------------------------------------------------------
+
+Add to CRON with
+
+	# crontab -e
+
+Configuring the riak module
+---------------------------
+
+The riak module uses the following configuration options specified
+in `config/module_riak.php`. The defaults are listed:
+
+	$config = array(
+		'path' => 'riak-php-client/riak.php',
+		'host' => 'localhost',
+		'port' => 8098,
+		'bucket' => 'SimpleSAMLphp',
+	);
+
+Finally, the module can be specified as the Store in `config/config.php`
+with the following setting:
+
+		'store.type' => 'riak:Store',
+
diff --git a/modules/riak/hooks/hook_cron.php b/modules/riak/hooks/hook_cron.php
new file mode 100644
index 0000000000000000000000000000000000000000..cad1c6e3d5dd1d8e86d2a6e7fd5dfc65ec6dc295
--- /dev/null
+++ b/modules/riak/hooks/hook_cron.php
@@ -0,0 +1,53 @@
+<?php
+
+/*
+ * Copyright (c) 2012 The University of Queensland
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Written by David Gwynne <dlg@uq.edu.au> as part of the IT
+ * Infrastructure Group in the Faculty of Engineering, Architecture
+ * and Information Technology.
+ */
+
+
+/**
+ * Hook to run a cron job.
+ *
+ * @param array &$croninfo  Output
+ */
+function riak_hook_cron(&$croninfo) {
+	assert('is_array($croninfo)');
+	assert('array_key_exists("summary", $croninfo)');
+	assert('array_key_exists("tag", $croninfo)');
+
+	if ($croninfo['tag'] !== 'hourly') return;
+
+	try {
+		$store = new sspmod_riak_Store_Store();
+		$result = $store->bucket->indexSearch('expires', 'int',
+		    1, time() - 30);
+		foreach ($result as $link) {
+			$link->getBinary()->delete();
+		}
+
+		SimpleSAML_Logger::info(sprintf("deleted %s riak key%s",
+		    sizeof($result), sizeof($result) == 1 ? '' : 's'));
+	} catch (Exception $e) {
+		$message = 'riak threw exception: ' . $e->getMessage();
+		SimpleSAML_Logger::warning($message);
+		$croninfo['summary'][] = $message;
+	}
+}
diff --git a/modules/riak/lib/Store/Store.php b/modules/riak/lib/Store/Store.php
new file mode 100644
index 0000000000000000000000000000000000000000..2127ffc50a8e34fbc3c210631f6872d1fea8fc07
--- /dev/null
+++ b/modules/riak/lib/Store/Store.php
@@ -0,0 +1,103 @@
+<?php
+
+/*
+ * Copyright (c) 2012 The University of Queensland
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Written by David Gwynne <dlg@uq.edu.au> as part of the IT
+ * Infrastructure Group in the Faculty of Engineering, Architecture
+ * and Information Technology.
+ */
+
+class sspmod_riak_Store_Store extends SimpleSAML_Store {
+	protected function __construct() {
+		$config = SimpleSAML_Configuration::getConfig('module_riak.php');
+
+		$path = $config->getString('path', 'riak-php-client/riak.php');
+		$host = $config->getString('host', 'localhost');
+		$port = $config->getString('port', 8098);
+		$bucket = $config->getString('bucket', 'simpleSAMLphp');
+
+		require_once($path);
+		$this->client = new RiakClient($host, $port);
+		$this->bucket = $this->client->bucket($bucket);
+	}
+
+	/**
+	 * Retrieve a value from the datastore.
+	 *
+	 * @param string $type  The datatype.
+	 * @param string $key  The key.
+	 * @return mixed|NULL  The value.
+	 */
+	public function get($type, $key) {
+		assert('is_string($type)');
+		assert('is_string($key)');
+
+		$v = $this->bucket->getBinary("$type.$key");
+		if (!$v->exists()) {
+			return (NULL);
+		}
+
+		$expires = $v->getIndex('Expires', 'int');
+		if (sizeof($expires) && (int)array_shift($expires) <= time()) {
+			$v->delete();
+			return (NULL);
+		}
+
+		return (unserialize($v->getData()));
+	}
+
+
+	/**
+	 * Save a value to the datastore.
+	 *
+	 * @param string $type  The datatype.
+	 * @param string $key  The key.
+	 * @param mixed $value  The value.
+	 * @param int|NULL $expire  The expiration time (unix timestamp), or NULL if it never expires.
+	 */
+	public function set($type, $key, $value, $expire = NULL) {
+		assert('is_string($type)');
+		assert('is_string($key)');
+		assert('is_null($expire) || (is_int($expire) && $expire > 2592000)');
+
+		$v = $this->bucket->newBinary("$type.$key", serialize($value), 'application/php');
+		if (!is_null($expire)) {
+			$v->addIndex("Expires", "int", $expire);
+		}
+
+		$v->store();
+	}
+
+	/**
+	 * Delete a value from the datastore.
+	 *
+	 * @param string $type  The datatype.
+	 * @param string $key  The key.
+	 */
+	public function delete($type, $key) {
+		assert('is_string($type)');
+		assert('is_string($key)');
+
+		$v = $this->bucket->getBinary("$type.$key");
+		if (!$v->exists()) {
+			return;
+		}
+
+		$v->delete();
+	}
+}