Skip links

Writing an OAuth Provider in PHP

19 October 2011 21:45 - by Freek Lijten - 30 comments

Tags: , ,

Earlier I wrote about consuming an OAuth service. This kind of blog posts is reasonably common on the internet. What seems to be less common is posts on providing an OAuth service. Today I hope to share some light on the topic by offering an extensive post on exactly that. As well as my first article the provider will use PECL's OAuth package.

Contents

Usually I don't offer a contents section in an article, but this one is quite long. To give you an idea what to expect, here it is:

  1. The code in this article
  2. OAuth, why and what?
  3. Getting started, offering a consumer key and secret
  4. Setting up the first endpoint
  5. The consumer handler
  6. The timestamp and nonce handler
  7. Outputting the request token
  8. Authorising the request token
  9. Getting an access token
  10. An actual API call
  11. Omissions
  12. References

The Code in this article

As I already wrote, this will be a long article. I was torn (how's that for a heavy term ;) ) between offering as much code as possible and not making this article any longer than strictly necessary. I also wanted to do more than offer some snippets of code which have to be glued together.

As a solution to these problems I decided to work out a full example and make it public through github. It is a work in progress but you can find it here. I will still provide code snippets during this article, but the repository offers a full and working (after setup) example. All code in this article will be based on the example folder that can be found there. If something in the example isn't working, I created a bug. In that case, please contact me trough the contact form or in the comments.

OAuth,  why and what?

If you don't know about OAuth at all, I suggest you start by reading my article on consuming an OAuth service which offers a short explanation on the concept. It gives an explanation of a typical use case as well. After that it would be wise to skim the OAuth specification here.

Since you took my advice (you did, didn't you), you're now up to speed with OAuth. Lets start our journey through OAuth providing land. 

Getting started, offering a consumer key and secret

The very first we need to facilitate is a location where OAuth consumers can apply for a consumer key and secret. The code for this isn't too complicated and my example's implementation doesn't offer a UI but it will do for this article's sake.

$Consumer = new OAuthConsumerModel(Configuration::getDataStore());
$Consumer->setConsumerCreateDate(time());
$Consumer->setConsumerKey(OAuthProviderWrapper::generateToken());
$Consumer->setConsumerSecret(OAuthProviderWrapper::generateToken());
$Consumer->save();

echo "Consumer key: " . $Consumer->getConsumerKey() . "
Consumer secret: " . $Consumer->getConsumerSecret();

In a real world application you would ask a potential consumer a whole lot of questions. The least you'll want is contact information. Remember, once granted a consumer key and secret, a consumer can interact with your service in an almost seamless way. The consumer will be assumed trustworthy by your users, you'll have to make sure that that's justified.

One small note on the Configuration and Provider static functions you may have noticed in the code snippet above. The ProviderWrapper functions will be talked about in detail. The Configuration::getDataStore() is my current solution to have one place where a datastore (mysql in my case) connection is defined. Ideally I would use dependency injection only to pass the datastore around, but because of the callbacks (talked about later in this article) this isn't possible.

Setting up the first endpoint

The first endpoint we need to offer to a consumer is the request token endpoint. The part that executes all the necessary checks and outputs the actual token information looks like this:

$Provider 	= new OAuthProviderWrapper(OAuthProviderWrapper::TOKEN_REQUEST);
$response 	= $Provider->checkOAuthRequest();
if ($response !== true) {
	echo $response;
	exit;
}

try {
	$Provider->outputRequestToken();
} catch (ProviderException $Exception) {
	echo $Exception->getMessage();
}

As you can see the Wrapper class does a lot of work for us. This is way too magical for this article but it demonstrates how much can be abstracted away. 

Ignore the checkOAuthRequest function for now, its purpose and workings will get clear later on in this article. We'll look at the OAuthProviderWrapper's constuctor first. Upon construction the wrapper initialises an OAuthProvider class and sets callback functions disregarding the constant the wrapper is created with.

public function __construct($mode)
{
	$this->Provider = new OAuthProvider();
	$this->Provider->consumerHandler(array($this,'consumerHandler'));
	$this->Provider->timestampNonceHandler(array($this,'timestampNonceHandler'));

	if ($mode == self::TOKEN_REQUEST) {

		$this->Provider->isRequestTokenEndpoint(true);
                //enforce the presence of these parameters
		$this->Provider->addRequiredParameter("oauth_callback");
		$this->Provider->addRequiredParameter("scope");
	} ...
}

As you can see the two callback methods are consumerHandler and timestampNonceHandler. We also need to tell the OAuthProvider that we're dealing with a request token. If we don't a third callback is expected, but more about that later.

You'll also notice the two calls to addRequiredParameter. This tells the OAuthProvider object we expect scope and oauth_callback to be present. If they're not, any request to our request token endpoint should be considered invalid.

The consumer handler

The first of the two callback functions we specified in the previous example is the consumer handler. This will check if the consumer information that is provided with the current request leads to a known consumer. This function is expected to return either of the following PECL OAuth constants: OAUTH_CONSUMER_KEY_UNKNOWN, OAUTH_CONSUMER_KEY_REFUSED or OAUTH_OK. Part of the full function is seen below:

public static function consumerHandler($Provider)
{
	try {
		$OAuthConsumer = OAuthConsumerModel::loadFromConsumerKey($Provider->consumer_key, Configuration::getDataStore());
	} catch (DataStoreReadException $Exception) {
		return OAUTH_CONSUMER_KEY_UNKNOWN;
	}

	$Provider->consumer_secret = $OAuthConsumer->getConsumerSecret();
	return OAUTH_OK;
}

So what happens? A factory method is used to load a Model class. If the consumer key is unknown, the model will throw an exception and an OAuth constant is returned. If the model is found, the Provider that we received trough callback is informed of the corresponding secret. The Provider will need this to verify the signature later on as it only received the consumer key from the Consumer. Finally we let the Provider know all is OK!

You might be wondering what the OAUTH_CONSUMER_KEY_REFUSED could be used for. This constant informs the consumer that its consumer key and secret are (temporarily) not considered valid anymore. This could happen if a provider supports blacklisting or limits request per unit of time. Both options are not found in this example at this moment.

The timestamp and nonce handler

The second callback function checks two things: the timestamp and the nonce (the setter method's name is kind of a give away :) ). Both the nonce and the timestamp are required by the OAuth specification. The nonce and timestamp are a barrier against replay attacks. The nonce is basically there to prevent someone listening to a conversation between a consumer and provider from storing and repeating a succesful request.

An attacker can't forge a request since he lacks the shared secrets, but a successfully call to an API which results in data could be eavesdropped upon and made over and over again. With a number in place that changes every request (thus changing the signature which can only be created with the shared secret which is not in the attackers possession), eavesdropping is rather useless. The request has been sent already and won't be valid a second time.

This following quote comes from the RFC and tells us more about the nonce and timestamp:

A nonce is a random string, uniquely generated by the client to allow the server to verify that a request has never been made before and helps prevent replay attacks when requests are made over a non-secure channel. The nonce value MUST be unique across all requests with the same timestamp, client credentials, and token combinations.

To avoid the need to retain an infinite number of nonce values for future checks, servers MAY choose to restrict the time period after which a request with an old timestamp is rejected.

With that in mind look at the following code:

public static function timestampNonceHandler($Provider)
{
	if (time() - $Provider->timestamp > 300) {
		return OAUTH_BAD_TIMESTAMP;
	}

	if (OAuthNonceModel::nonceExists($Provider->nonce, Configuration::getDataStore())) {
		return OAUTH_BAD_NONCE;
	}

	$OAuthNonce = new OAuthNonceModel(Configuration::getDataStore());
	$OAuthNonce->setId($Provider->nonce);
	$OAuthNonce->setNonceConsumerKey($Provider->consumer_key);
	$OAuthNonce->setNonceDate(time());
	$OAuthNonce->save();

	return OAUTH_OK;
}

As you can see we ignore all requests older than 5 minutes. This quite a large window, but we must keep in mind that servers are most likely not synchronised at the exact same time. If the timestamp checks offers no problems, we check to see if the nonce already exists in our database. If it does we invalidate the request, if it doesn't we create a new model and save it. Return values consist once again of the OAuth package predefined constants

Outputting the request token

Untill now we've seen two handlers being defined but how are they called? For that a seperate function exists which does little more than call the same function at the OAuthProvider. This function is called at the endpoint after construction (see above if you forgot). 

public function checkOAuthRequest()
{
	try {
		$this->Provider->checkOAuthRequest();
	} catch (Exception $Exception) {
		return OAuthProvider::reportProblem($Exception);
	}
	return true;
}

The function call above will also result into a check for the validity of the received signature and the presence of required parameters (oauth_callback and scope). Luckily for us those happen internally and are not setup by ourself. We're now at a point where a request has come in and all we needed to check has been checked. We therefore can issue a new request token. This function looks like this:

public function outputRequestToken()
{
	$token 		= OAuthProviderWrapper::generateToken();
	$tokenSecret 	= OAuthProviderWrapper::generateToken();
	$RequestToken 	= new OAuthRequestTokenModel(Configuration::getDataStore());

	$RequestToken->setToken($token);
	$RequestToken->setTokenSecret($tokenSecret);
	$RequestToken->setTokenDate(time());
	$RequestToken->setTokenConsumerKey($this->Provider->consumer_key);
	$RequestToken->setTokenCallback($_GET['oauth_callback']);
	$RequestToken->setTokenScope($_GET['scope']);
	$RequestToken->save();
	
	echo "oauth_token=$token&oauth_token_secret=$tokenSecret&oauth_callback_confirmed=true";
}

Nothing really exciting is happening here. We use the generateToken function from the OAuthProvider to do our hard work, store some data in a model and return a string per the rfc's specifications (see the end of this paragraph). The endpoint exits its executing after this call and we've finished the first part of our OAuth dance with the consumer!

Authorising the request token

Now the consumer has received a request token and secret from us the second part of the dance starts. The consumer must redirect its user to our service's authorisation page. The user must be made very much aware of what he is about to consent to. A provider should double check identy by logging in once again. Even when a user is already logged in, it is advisible to do so. See what the RFC has to say on this:

However, the server MUST first verify the identity of the resource owner.

When asking the resource owner to authorize the requested access, the server SHOULD present to the resource owner information about the client requesting access based on the association of the temporary credentials with the client identity. When displaying any such information, the server SHOULD indicate if the information has been verified.

When a user does login and grants permission we will lookup the user id and store it our request token model. Secondly a verification code is generated and also stored at the request token model. Then the user is redirected back to the callback URL that was provided in the initial request. Below you see the code starting from the part where the user is already looked up in the database:

if ($row['user_password'] != $_POST['user_password']) {
	echo "You hacker, be gone!";
	exit;
}

$verificationCode = OAuthProviderWrapper::generateToken();
$RequestToken->setTokenVerificationCode($verificationCode);
$RequestToken->setTokenUserId($row['user_id']);
$RequestToken->save();

header( 'location: ' . $RequestToken->getTokenCallback() . '?oauth_token=' . $RequestToken->getToken() . '&oauth_verifier=' . $verificationCode );

As you can see this isn't the largest and hardest part of the dance so that leaves us with time for questions :) What is the use of the verification code you ask? The verification code is sent back to the consumer to ensure that the user granting access is the same user that will be coming back to complete the last part of our OAuth dance. Now we've issued a request token and the user has authorised it, there is only one more step before our API can be used.

Getting an access token

The last part of our dance evolves around the access token. Our wrapper at this endpoint is constructed with a different constant as before making sure the correct code in the constructor will be reached:

$this->Provider = new OAuthProvider();
$this->Provider->consumerHandler(array($this,'consumerHandler'));
$this->Provider->timestampNonceHandler(array($this,'timestampNonceHandler'));

if ($mode == self::TOKEN_REQUEST) {
...
} else if ($mode == self::TOKEN_ACCESS) {
	$this->Provider->tokenHandler(array($this,'checkRequestToken'));
} ...

Earlier I mentioned the existence of a third handler. This is the tokenHandler which is required for any non-request token request. Inside the request token handler we can perform checks before issuing an access token, so lets see what our trusted RFC has to say on this topic:

The server MUST verify (Section 3.2) the validity of the request, ensure that the resource owner has authorized the provisioning of token credentials to the client, and ensure that the temporary credentials have not expired or been used before. The server MUST also verify the verification code received from the client.

This is how that looks in code:

public static function checkRequestToken($Provider)
{
	$DataStore = Configuration::getDataStore();

	//Token can not be loaded, reject it.
	try {
		$RequestToken = OAuthRequestTokenModel::loadFromToken($Provider->token, $DataStore);
	} catch (DataStoreReadException $Exception) {
		return OAUTH_TOKEN_REJECTED;
	}

	//The consumer must be the same as the one this request token was originally issued for
	if ($RequestToken->getTokenConsumerKey() != $Provider->consumer_key) {
		return OAUTH_TOKEN_REJECTED;
	}

	//Check if the verification code is correct.
	if ($_GET['oauth_verifier'] != $RequestToken->getTokenVerificationCode()) {
		return OAUTH_VERIFIER_INVALID;
	}

	$Provider->token_secret = $RequestToken->getTokenSecret();
	return OAUTH_OK;
}

If the the checkOAuthRequest in the access token endpoint doesn't fail the outputAccessToken function is called. This looks a lot like the outputRequestToken function. It has one addition however, the request token is no longer necessary so it is deleted:

public function outputAccessToken()
{
	$token 			= OAuthProviderWrapper::generateToken();
	$tokenSecret 	= OAuthProviderWrapper::generateToken();
	$AccessToken 	= new OAuthAccessTokenModel(Configuration::getDataStore());

	$AccessToken->setAccessToken($token);
	$AccessToken->setAccessTokenSecret($tokenSecret);
	$AccessToken->setAccessTokenDate(time());
	$AccessToken->setAccessTokenConsumerKey($this->Provider->consumer_key);
	$AccessToken->setAccessTokenUserId($RequestToken->getTokenUserId());
	$AccessToken->setAccessTokenScope($RequestToken->getTokenScope());
	$AccessToken->save();
	
	//The access token was saved. This means the request token that was exchanged for it can be deleted.
	$RequestToken->delete();	

	echo "oauth_token=$token&oauth_token_secret=$tokenSecret";
}

Hurray we have access token! Or more precisely: our consumer does. At this point there is only one small thing left. Securing our API with OAuth.

An actual API call

At this point the consumer has all the data it needs to make an authorised call to our API and get the personalised and authorised data. If you check out the example you'll notice there is a user_messages table. Let see how our very simple API would look if it wishes to open up that data to the world:

$Provider 	= new OAuthProviderWrapper(OAuthProviderWrapper::TOKEN_VERIFY);
$response 	= $Provider->checkOAuthRequest();
if ($response !== true) {
	echo $response;
	exit;
}

$userId      = $Provider->getUserId();
$sql         = "SELECT * FROM `user_messages` WHERE `user_id` = '" . $userId . "'";
$result      = Configuration::getDataStore()->query($sql);

//Token is valid, lets output something
$returnValue = "";
while ($row = $result->fetch_assoc()) {
	$returnValue .= "" . $row['message_text'] . "";
}
$returnValue .= "";
echo $returnValue;

The code above once again constructs an OAuthProviderWrapper, but this time with the TOKEN_VERIFY constant. This tells the constructor our current token handler is the checkAccessToken function. Indirectly this is called trough the checkOAuthRequest function. If authorisation is successful we output some data. The output part isn't interesting, but lets take a look at the checkAccessToken as our final code example:

public static function checkAccessToken($Provider)
{
	$DataStore = Configuration::getDataStore();

	//Try to load the access token
	try {
		$AccessToken = OAuthAccessTokenModel::loadFromToken($Provider->token, $DataStore);
	} catch (DataStoreReadException $Exception) {
		return OAUTH_TOKEN_REJECTED;
	}

	//The consumer must be the same as the one this request token was originally issued for
	if ($AccessToken->getAccessTokenConsumerKey() != $Provider->consumer_key) {
		return OAUTH_TOKEN_REJECTED;
	}

	$Provider->token_secret = $AccessToken->getAccessTokenSecret();
	return OAUTH_OK;
}

If the token can't be loaded, or if the consumer isn't the one we expect the token is rejected, but otherwise there is nothing wrong. Basically this all there is to it. We've just checked the last request we needed to check and data has been provided to the consumer. Please read the omissions paragraph to see what is missing or can be improved, but otherwise be happy you've read through all these words :)

Omissions

While reading along you might have noticed stuff missing once or twice. You should definitely take a look into blacklisting consumers and you must take a look at limiting access by a unit of time. Also we let the consumer specifically pass us a scope. Yet we did nothing with it. Depending on the amount of different datamodels you want to open up through your API you should also take a look into that direction. Obviously it would be brilliant if this article had covered this as well, but it is long enough already. Besides, there must be something left for you to figure out :)

References

While writing the proof of concept of the OAuth provider I read Rasmus Lerdorfs post on providing OAuth and while rewriting that proof of concept into a structured piece of code I stumbled accross Lorna Jane Mitchells series on the topic. Though an RFC is not always fun to read, that too was invaluable. 

An extremely well written and comprehensive guide to general OAuth can be found here. Finally the documentation to the OAuth PECL package (scarsely present, certainly as compared to many other parts of the PHP.net site) can be found here.

Share this post!

Comments

  1. Dave Dave wrote on 31 October 2011 04:48

    I have a network of forums, with users who are active on several of them. I would like to give them one ID and allow access to my whole network. So by providing an OAuth service, you wouldn't have to use Twitter, you can actually roll you own authentication that could be used across several site?

  2. efe efe wrote on 31 October 2011 09:56

    Thanks

  3. Freek Lijten Freek Lijten wrote on 31 October 2011 13:42

    Hey Dave,

    OAuth is not the best solution to the problem you just described. You want some sort of Single Sign-on (SSO) solution. OpenID might be what you really want as far as I can deduce from your reaction.

    Just for the record, OAuth and OpenID are not the same. This article explains why quite well.

    However if you're sure you want to use OAuth, I think other people do it too. I have read of people using OAuth as authentication meganism at least, but I haven't seen or used this actively. If examples for that use Twitter or Google for instance, they could indeed be replaced by your own OAuth provider perfectly well.

    I'm sorry I can't be of more help, but I've never implemented an OpenID server or used OAuth in that way before :)

  4. Eric Wang Eric Wang wrote on 13 November 2011 14:15

    Hi,Freek Lijten.I love this blog and I want to ask you some questions about OAuth.

    I'am developing an android application,and I have a small website,which can provide some RESTful API.I want to add OAuth to these API.And I need2-legged OAuth,because I want user could directly input username and password,by the android app, and finish the OAuth flow.

    My question is,how should I build this2-legged OAuth interface by php?Thank you.

  5. Freek Lijten Freek Lijten wrote on 14 November 2011 13:54

    Hey Eric,

    First of all: Thanks! :)

    I understand you're going to let users enter usernames and passwords inside the application you are building. If your users should input a username and password, why would you bother going trough the hassle of OAuth at all? One of the main points of OAuth is avoiding exactly that. It is easier and probably better to simply provide a secure URL using SSL/TLS (https) so users can safely transfer their login data over the internet.

    I don't know of a lot of 2-legged OAuth providers, but I have worked with Google's API's and whatthey call 2-legged OAuth before (see this link to their documentation).

    The way it works is as follows. Basically the whole authentication cycle resulting in an access token is not used. An access token is not a requirement when accessing a protected resource. Simply having the consumer key and secret is enough to make a signed and successful request to a protected resource. This means that they shouldn't be exposed to anyone who does not need to know about it.

    Using this technique in a mobile app sounds like a bad idea to me, because the mobile app's source code is essentially available to the public. By decompiling the source code and filtering out the consumer key and secret, everybody can access the data.

    Having said that, I don't think there is an official specification for 2-legged OAuth at all. I believe other parties have different definitions for what 2-legged OAuth actually means or should mean. As I said before I think you'd better look for a simpler solution in this specific case anyway.

    Cheers,

    Freek

  6. xhinking xhinking wrote on 20 November 2011 14:56

    Thank you Freek!

    You are right, I don't need Oauth in my project:) HTTPS is enough.

    Thank you again for your patient reply!Looking forward to your new blog.

  7. Wade Sweatt Wade Sweatt wrote on 25 April 2012 00:27

    I am trying to get a request token from my provider using this URL:

    MYSERVER/oauth/request_token?oauth_callback=http://localhost/client/callback.php

    My php client is running locally on my mac's web server. The array comes back basically empty from the provider, and I get this string from OAuth:

    oauth_problem=parameter_absent&oauth_parameters_absent=oauth_consumer_key%26oauth_signature%26oauth_signature_method%26oauth_nonce%26oauth_timestamp

    I understand that this means I'm missing the consumer key, signature, nonce, and timestamp. However, I don't think the client should be providing this. My conclusion is that there is something wrong with the provider side of things. In my provider, I call these two functions when asking for a request token:

    /
    This function check the handlers that we added in the constructor * and then checks for a valid signature */ public function checkRequest(){ now that everything is setup we run the checks / try{ $this->oauth->checkOAuthRequest(); } catch(OAuthException $E){ echo OAuthProvider::reportProblem($E); $this->oauth_error = true; } }

    //AND

    public function generateRequestToken(){
    if($this->oauth_error){ return false; } $token = sha1(OAuthProvider::generateToken(20,true)); $token_secret = sha1(OAuthProvider::generateToken(20,true)); $callback = $this->oauth->callback; Token::createRequestToken($this->consumer, $token, $token_secret, $callback); return "authentification_url=".$this->authentification_url."&oauth_token=".$token."&oauth_token_secret=".$token_secret."&oauth_callback_confirmed=true"; }

    So, I should be getting the information back via the return statement there at the bottom. Any ideas why it is asking for the key, sig, nonce, and timestamp, and why it won't return the request token, signature, and authentication url, etc?

    Thanks so much!

    Wade

  8. Wade Sweatt Wade Sweatt wrote on 25 April 2012 00:33

    Sorry about the formatting of the code above. It did not look that way in the submit box. If it is not readable, I would be glad to email you something better formatted. Thanks for your help either way.

    Wade

  9. shivani shivani wrote on 19 November 2012 08:49

    Dave, can you please write php oauth provide for Salesforce as i am not able to write wsdl which will invoke oauthprovider php class.

  10. Hanley Hansen Hanley Hansen wrote on 30 December 2012 01:14

    For anyone having trouble with the OAuth Provider class make sure you install the OAuth PECL extension.

    I used this link to install it on CentOS 6 and I got everything working fine now.

    Regards, Hanley Hansen

  11. Vincenzo Vincenzo wrote on 04 July 2013 13:24

    Hi Freek, thanks for this guide...I have some problems and i hope you can help me! the code work well when i try to run Oauth on my local server that run with xampp for MAC, but if I put the code on remote server Debian with apache2, I have a little problems.. the get_request_token is very slow, if i try to call the file get_request_token.php i will wait around three minutes before show the login form! also in the next step when i try to login with the correct credentials. I saw also in the apache error log this error: Access denied for user 'www-data'@'localhost' (using password: NO) in .../OAuth/lib/Configuration.php on line

    So i think it could have lost the database connection.

    On the remote server i have https and ssl, I tried to disable https and ssl but i have the same problems.

    For install oauth on debian with php5.x i used this commands: apt-get install php5-dev php-pear apt-get install make libpcre3-dev apt-get install libcurl3-dev pecl install oauth vi /etc/php5/conf.d/oauth.ini

    Added the follow line to php.ini: extension=oauth.so

    For mac i followed this guide: http://www.sumardi.net/2011/06/04/installing-oauth-extension-in-xampp-for-mac-os-x/

    Have you an idea? Do you know if on Debian i have to set more options on the server or i have to install other libraries?

  12. enceinte sans fil enceinte sans fil wrote on 07 November 2013 20:59

    What's up, I read your blog regularly. Your humoristic style is witty, keep up the good work!

  13. trampoline enfant trampoline enfant wrote on 07 November 2013 23:25

    I was able to find good advice from your blog articles.

  14. www.disquedurmultimedia.info www.disquedurmultimedia.info wrote on 08 November 2013 01:02

    You can definitely see your enthusiasm in thhe article you write. The sector hopes for even moe passionate writers such as you who aren't afraid to mention how they believe. All the time go after your heart.

  15. touchpascher.info touchpascher.info wrote on 13 November 2013 13:04

    Excellent site you have here.. It's hard to find high quality writing like yours nowadays. I really appreciate individuals like you! Take care!!

  16. tapis d'eveil tapis d'eveil wrote on 13 November 2013 22:31

    Hmm is anyone elsae encountering problems with the images on this blog loading? I'm trying to determine if its a problem on my end or if it's the blog. Any feedback would be greatly appreciated.

  17. brosse a dent electrique brosse a dent electrique wrote on 17 November 2013 01:29

    Thank you for some other informative web site. The place else coulod I am getting that type of information written in such an ideal manner?

    I have a undertaking that I am just now runninng on, and I have been at the look out for such info.

  18. http://www.designerhandbagsplaza.com/ http://www.designerhandbagsplaza.com/ wrote on 27 November 2013 21:09

    bookmarked!!, I like your blog!

  19. designerhandbagsplaza.com designerhandbagsplaza.com wrote on 18 December 2013 13:49

    Hey! Do yyou know if they make any plugins to protect against hackers? I'm kinda paranoid about losing everything I've worked hatd on. Any suggestions?

  20. waarom geen magento waarom geen magento wrote on 31 December 2013 19:13

    Ben nog vrij nieuw op gebied van magento dus zal een simpele vraag zijn maar zoek me een ongeluk naar de juiste oplossing. Wat ik graag zou willen weten:

    wat is nou de beste oplossing/manier om op server A een shop te bouwen (volledig af) en daarna over te zetten naar server B (als vervanging van een oude shop).

    Vragen die bij mij hier over op komen zijn: kan een sql backup zo maar overgezet worden en wat moet er van de ftp overgezet worden?

  21. eidwvmzvhz eidwvmzvhz wrote on 19 January 2014 00:56

    glkblgsfflmjkufo, <a href="http://www.ontcvripcz.com/">cyogndqocb</a>

  22. mold removal spray mold removal spray wrote on 20 January 2014 11:28

    This post is actually a pleasant one it helps new internet viewers, who are wishing in favor of blogging.

  23. plpzhbzlou plpzhbzlou wrote on 21 January 2014 14:01

    sggxhgsfflmjkufo, <a href="http://www.esxxumeabs.com/">kuiswsjpkm</a>

  24. tyszafccxe tyszafccxe wrote on 24 January 2014 16:45

    szrkcgsfflmjkufo, http://www.xvkwzpjaja.com/ zalzmgjled

  25. djfluljxfe djfluljxfe wrote on 29 January 2014 19:26

    winfegsfflmjkufo, <a href="http://www.awtgnzteul.com/">rbbktmxqoe</a> , [url=http://www.mmwffjmsyo.com/]oluwovtupo[/url], http://www.kywtkassae.com/ rbbktmxqoe

  26. GD45 GD45 wrote on 16 April 2014 05:14

    GY

  27. pirate bay pirate bay wrote on 20 April 2014 09:41

    But in 2004 the site was run separately just as one independent organization. Sites for example i - Tunes have proven that despite the huge number of pirate sites that folks are still pleased to pay to legally download music in the Internet. Taking a cue from that, if publishers will make their ebooks available to a larger audience instantly, it could and will encourage readers to go for that authentic version.

  28. muscle building diet plan for men muscle building diet plan for men wrote on 03 May 2014 11:00

    muscle building diet plan for men

    Over-time with frequent washing and following a really healthy diet in between you can lose weight but the main purpose would be to enable your body expel toxins that restrict weight control. Infact, you could feel mild and quite empowered following the cleansing.

    super citrimax clinical strength

    After the three times you can slowly introduce more foods but make certain they are healthier. Heading back to sweets and unhealthy foods and fat can simply undo whatever you've completed. Repeat the 3 day cleanse the following month and research somewhat. Attempt one day of liquid fasting about the second-day or lengthen the 3 day detox diet for a few more times. It will improve your health.

    appetite suppressant herbs

    Dinner: Have another big salad or perhaps a full bowl of steamed veggies with brown rice, quinoa,or millet. Incorporate lots of chopped fresh herbs for flavour.

    Buy Yacon Syrup Intake of monounsaturated and polyunsaturated fat can help reduce blood cholesterol when substituted for fatty foods in the diet.

    buy yacon syrup

    Preparation may be the key

    buy yacon syrup

    Before this current finding the bananas was recommended as the most nutrient rich meals. It'd been regarded for the exceptionally strong antioxidant qualities.

    buy yacon syrup

    Lessen your intake of processed foods, refined, junk foods, sugars and food containing it, and red or greasy meat. Improve your consumption of vegetables and fruit. You are able to change the coffee and standard teas using a coffee substitute

    Buy Yacon Syrup your immune-system, your storage and not only this can benefit from having fat.

    It is an incredibly poor idea to remove fat completely from your own diet. "Good" fats are necessary. These good fats come from such things as cool, canola oil, extravirgin essential olive oil, flaxseed, nuts, walnuts and Enova Oil -water bass. Getting rid of the wrong sort and consuming the right kind of fat is what's necessary.

  29. napisa_ o tym napisa_ o tym wrote on 12 May 2014 10:25

    This design is steller! You definitely know how to keep a reader amused. Between your wit and your videos, I was almost moved to start my own blog (well, almost...HaHa!) Fantastic job. I really enjoyed what you had to say, and more than that, how you presented it. Too cool!

  30. military education benefits military education benefits wrote on 27 July 2014 07:16

    Hey there! I know this is kind of off topic but I was wondering if you knew where I could locate a captcha plugin for my comment form? I'm using the same blog platform as yours and I'm having trouble finding one? Thanks a lot!

Leave a comment!

Italic and bold

*This is italic*, and _so is this_.
**This is bold**, and __so is this__.

Links

This is a link to [Procurios](http://www.procurios.nl).

Lists

A bulleted list can be made with:
- Minus-signs,
+ Add-signs,
* Or an asterisk.

A numbered list can be made with:
1. List item number 1.
2. List item number 2.

Quote

The text below creates a quote:
> This is the first line.
> This is the second line.

Code

A text block with code can be created. Prefix a line with four spaces and a code-block will be made.