Jump to content

PHP and Token Authentication


mds1256
Go to solution Solved by Jacques1,

Recommended Posts

Hi

 

I am trying to get my head around how to properly implement token authentication for my JSON api.

 

It seems like the concept is:

 

  1. use username and password on a /login POST api over SSL to then compare with the values in the DB for username and hashed password.
  2. If it authenticates ok then generate a random access token (stored in the DB against the user and have an expiry date/time associated with it) and return this access token to the user
  3. Then on every client request send the access token to the server and check this value with that is stored and validate against the expiry
  4. If this matches and is still valid then process the API request and return the data requested
  5. If it doesn't match then generate a 401 error and return this to the client and handle re-logging in.

So I get how that part of it works but I see apps etc that use APIs that stay logged in for ever basically. So do you think they hold onto the username and password in the client app for when the server access token expires and it then resends the username and password to get a new access token?

 

I have read that the client application should never remember the username and password and you should use a concept of 'refresh tokens'.

 

How do these work? Also refresh tokens should also expire (after a longer period of time than the access token) so how does this concept work?

 

Thanks

Link to comment
Share on other sites

So I get how that part of it works but I see apps etc that use APIs that stay logged in for ever basically. So do you think they hold onto the username and password in the client app for when the server access token expires and it then resends the username and password to get a new access token?

 

I have read that the client application should never remember the username and password and you should use a concept of 'refresh tokens'.

 

How do these work? Also refresh tokens should also expire (after a longer period of time than the access token) so how does this concept work?

While the client could hold on to the credentials, it shouldn't. Refresh tokens are the better solution.

 

Exactly how access and refresh tokens work depend on your application. Access tokens could be good for a couple minutes or an hour and may or may not be limited to one per user, while refresh tokens are good for a lot longer (possibly indefinitely) and typically have one per device or web session. Since refresh tokens are so powerful they should also be revokable.

 

Access tokens are basically like short-lived sessions, so their time limits should be pretty short - short enough so that they don't live long, but long enough that the client is spending more time issuing requests than refreshing access. The lifetime of refresh tokens are directly tied to how often the user is required to authenticate with your system, so the first question to answer is whether you want to force the user to enter their credentials ever again after the first time.

 

As for the process,

1. Client authenticates and gets an access token with its expiration.

2. Client can then request a refresh token if it wants one.

3. Client uses access token until shortly before it expires, and/or continues until the API returns 401s.

4. To refresh, client uses the refresh token with a specific endpoint to get a new access token (if it hasn't been revoked).

5. Refresh endpoint returns a new access token (and expiration) and client resumes using that.

 

Remember that you can always look around to other APIs, like OAuth, to see how they do it.

Link to comment
Share on other sites

Thanks for that.

 

The example I am going from is my Gas and Electric phone application - without knowing how it works exactly it seems that I login once and haven't had to log in again (been over 6 months since first logged in).

 

Also I believe for example Facebook app works the same way where you login once and it doesn't ask you again?

 

So just wondering how this would be implemented - I can see how using the refresh tokens like you have explained but I have also read that refresh tokens should expire at some point too?

 

Also what should an access token be made up from - could I just generate a totally random string or should it do some hashing based on a user id and time generated for example and then use the server to decode this to see if it matches the data or should it just check to see if the access token matches the same string in the access_token column in the database.

 

Sorry if these questions are basic but just trying to get my head around the concept of a properly scalable authentication system for an API

Link to comment
Share on other sites

Remember that you can always look around to other APIs, like OAuth, to see how they do it.

 

Or rather: Use them.

 

Reinventing OAuth might be a nice project if you're interested in protocol design itself, but it's a waste of time and a significant risk if you try to use your own protocol as an ad-hoc solution. Misunderstandings and bugs can be fatal in a security context.

 

OAuth 2.0 is an established and well-tested protocol which should cover just about every scenario. Use it.

  • Like 2
Link to comment
Share on other sites

The example I am going from is my Gas and Electric phone application - without knowing how it works exactly it seems that I login once and haven't had to log in again (been over 6 months since first logged in).

When I say to look at examples, I mean look at developer documentation. Not to use an app and guess how it works - find actual technical explanations.

 

But actually implementing OAuth would probably be the best thing for you to do. Like real OAuth. According to the specs.

 

So just wondering how this would be implemented - I can see how using the refresh tokens like you have explained but I have also read that refresh tokens should expire at some point too?

They can expire, sure. Like I said it depends on your application.

 

Also what should an access token be made up from -

Random string.
Link to comment
Share on other sites

Or rather: Use them.

 

Reinventing OAuth might be a nice project if you're interested in protocol design itself, but it's a waste of time and a significant risk if you try to use your own protocol as an ad-hoc solution. Misunderstandings and bugs can be fatal in a security context.

 

OAuth 2.0 is an established and well-tested protocol which should cover just about every scenario. Use it.

 

I do agree, however there are many frameworks that can be added to the project and these add complexity if things go wrong - for example if i switch to a newer version of PHP and that framework is not compatible and the its not updated for several months, Is there a single source for the framework for PHP as the places I have looked (OAUTH site) seemed to have been created by someone and not an official framework?

 

In essence I want the most supposed framework there is for this - any pointers where to look.

Link to comment
Share on other sites

  • Solution

Both thephpleague/oauth2-server and bshaffer/oauth2-server-php are very active, have been around for a while and are in fact mentioned on the “official” site (if that helps).

 

But even if the project dies in a couple of years – so what? Switching to a different library is still much, much less work than writing your own from scratch and maintaining it (just look at the number of contributors and commits). You could even implement an abstraction layer (e. g. a couple of wrapper functions), so that the application doesn't rely on any library-specific features.

  • Like 1
Link to comment
Share on other sites

So I have been playing around with the framework from: bshaffer.

 

and have a few questions if you could help?

 

Reading the documentation I have managed to create a test auth system but is it advisable to not edit the frameworks source files? e.g. do I need to use the user table that it looks for by default or should I edit the code to look at my user table?

 

my auth page looks like and it takes post data of user name and password (as well as client name and client secret) and provides an access code which I can then use the api page (below the auth page) to validate the access code and provide the content, I can also submit a request to this page with the refresh token to then generate the new access token which I can store in my app for future requests:

<?php
	
// error reporting (this is a demo, after all!)
ini_set('display_errors',1);error_reporting(E_ALL);

// Autoloading (composer is preferred, but for this example let's just do this)
require_once('src/OAuth2/Autoloader.php');
OAuth2_Autoloader::register();

$dsn = "mysql:dbname=xxxxxxx;host=localhost";
$username = "xxxxxxx";
$password = "xxxxxxx";
// $dsn is the Data Source Name for your database, for exmaple "mysql:dbname=my_oauth2_db;host=localhost"
$storage = new OAuth2_Storage_Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));

// Pass a storage object or array of storage objects to the OAuth2 server class
$server = new OAuth2_Server($storage);

// Add the "Client Credentials" grant type (it is the simplest of the grant types)
$server->addGrantType(new OAuth2_GrantType_UserCredentials($storage));
$server->addGrantType(new OAuth2_GrantType_RefreshToken($storage));

// Handle a request for an OAuth2.0 Access Token and send the response to the client
$server->handleTokenRequest(OAuth2_Request::createFromGlobals(), new OAuth2_Response())->send();
	
	

?>

api page - post with passing in access token as well as client id and client secret:

<?php
	
// error reporting again
ini_set('display_errors',1);error_reporting(E_ALL);

// Autoloading again
require_once('src/OAuth2/Autoloader.php');
OAuth2_Autoloader::register();

// create your storage again
$dsn = "mysql:dbname=xxxxxxx;host=localhost";
$username = "xxxxxxx";
$password = "xxxxxxxxx";
$storage = new OAuth2_Storage_Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));

// create your server again
$server = new OAuth2_Server($storage);

// Handle a request for an OAuth2.0 Access Token and send the response to the client
if (!$server->verifyResourceRequest(OAuth2_Request::createFromGlobals(), new OAuth2_Response())) {
    $server->getResponse()->send();
    die;
}
echo json_encode(array('success' => true, 'message' => 'You accessed my APIs!'));	
	
	
?>

So the basis of OAUTH 2 it looks like what I was trying to do but I am only wanting to use a subset of its functionality so do I need to remove any files from the framework or is it safe to just leave them all and only implement the functionality I need to?

 

If I want the application to permanently stay logged in do I change the expiry date of the refresh token to like 6 months as the refresh token expiry seems to only come into play if there hasn't been any new request to refresh the access token (so if a user is actively using the app then it will generate a new refresh token frequently anyway - each time the access token expires) - so if the user hasn't used the app in 6 months then prompt them to login again? 

 

This seems reasonable to me.

 

It actually wasn't as difficult to implement compared to what I was reading on the internet (assuming the above code is ok - as its based on the documentation)

Link to comment
Share on other sites

Reading the documentation I have managed to create a test auth system but is it advisable to not edit the frameworks source files? e.g. do I need to use the user table that it looks for by default or should I edit the code to look at my user table?

 

You should not edit any libraries files. If you just want to change the table names, you can do that through the configuration parameter of the constructor. If you want to change the entire table structure (for whatever reason), you can create a subclass of OAuth2\Storage\Pdo, override the methods and use that subclass as your storage engine. Last but not least, you can write a storage engine from scratch by implementing the various storage interfaces (see the documentation).

 

 

 

So the basis of OAUTH 2 it looks like what I was trying to do but I am only wanting to use a subset of its functionality so do I need to remove any files from the framework or is it safe to just leave them all and only implement the functionality I need to?

 

You do not remove any files. A library is by definition a collection of features which you may or may not use. The features you don't use have no effect.

 

 

 

If I want the application to permanently stay logged in do I change the expiry date of the refresh token to like 6 months as the refresh token expiry seems to only come into play if there hasn't been any new request to refresh the access token (so if a user is actively using the app then it will generate a new refresh token frequently anyway - each time the access token expires) - so if the user hasn't used the app in 6 months then prompt them to login again?

 

If you essentially want no user interaction at all and instead delegate authentication almost entirely to the app, the password approach doesn't make much sense. Depending on your app and audience, 6 months may already exceed the total lifetime of an app instance.

 

There are many authentication options, not just passwords. There are client credentials (basically a single permanent refresh token), JWT Bearer Tokens etc.

Edited by Jacques1
Link to comment
Share on other sites

I see, so one last question (I hope).

 

Do you know if OAUTH 2 prevents use of already issued tokens, e.g. user1 had token 'aaabbb' 2 years ago and that expired but user2 now has that same token 'aaabbb' (really unlikely) but that token got compromised 2 years ago and someone just happens to test this token at exactly same time as user2 now having this valid token.

 

I think what I am getting at; does OAUTH 2 do a lookup of tokens already issued from the past before issuing a new one to prevent the same token value being issued?

Link to comment
Share on other sites

The tokens are generated with a cryptographically secure random number generator, so unless your operating system is fundamentally broken, the risk of any collisions is insignificant. It's as unlikely as somebody generating the same RSA key as the one you use for TLS.

 

Yeah true, i suppose it would be no different than someone just randomly creating a token value and submitting that - the chances of getting it correct is very slim!

Edited by mds1256
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.