12

I have an REST service on my webserver, written in php. I was wondering, what would be the best authentication (besides basic http access authentication). I've heared of token-based auth, and would like to ask if someone could explain the main steps.

  • On a GET: Is the token send visible? (isn't that unsafe?)
  • How do I make the token only valid for a specific time?
  • ...

Client: Android/Browser; Server: Apache, PHP5

hakre
  • 193,403
  • 52
  • 435
  • 836
Johannes Staehlin
  • 3,680
  • 7
  • 36
  • 50

3 Answers3

16

It can be done either way, and values in a GET request aren't really any more visible than values in a POST request. If anybody can "see" (i.e. intercept) the request, he can see everything you're sending. In the end an HTTP request is just a bunch of HTTP headers possibly followed by a body. The URL is send in the first GET /foo/bar HTTP/1.1 line, other values are just send in different, following lines.

So it's up to you where you expect your authentication token to be send. You can require it to be a query parameter that is appended to every request:

GET /foo/bar?user=123456&token=abcde...

To really use the HTTP protocol as intended though, you should use the Authorization HTTP header:

Authorization: MyScheme 123456:abcde...

The content of this header is entirely up to you. It usually specifies an authorization method like Basic, followed by whatever you want to require for authentication. This can simply be the username and password, a hash of them, an opaque token the client has obtained at some point or anything else really.

I'd recommend a token system or a request signing system, with the latter being very much preferred. In a request signing system, the client has to obtain a token from you. It then sends a hash of this token and certain characteristics of the request to authenticate the request, e.g. sha1(Token + Timestamp + Request URL + Request Body). Your server can validate this without the client having to send the token in plain text on each request.

How do I make the token only valid for a specific time?

You save the token server-side with an expiration timestamp and check against it.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • 1
    Thanks, I think I got the basic idea now. Just few more questions on that: 1. When the client obtains the token - this will be a 'simple json file' for example, contain "TOKEN_A"? 2. If the client only sends a hash, including the timestamp, how do I check on server side if the hash is valid? loop over possible hashs of the las X ms? – Johannes Staehlin Mar 01 '12 at 05:56
  • 4
    1. Yes, whatever fits your model best. Maybe the user needs to register on a website and copy&paste a token from there. Maybe you do that through an API as well, in which case a JSON response is fine. 2. The `Authorization` header needs to contain the user id and the token hash. The request also has to contain the timestamp, for example in the `Date` header, which is pretty standard. The hash would be based on that literal `Date` header. Your server just looks up the token for the user, makes sure the Date is within ± a few minutes of the current time and re-creates the same hash. – deceze Mar 01 '12 at 06:00
  • 2
    So basic idea is: instead of sending the token plain, I send you the hash and information A,B,C. The Server get's the token from UID, hashes it with information A,B,C. and checks if the hashes are the same?! - (+the time-validation staff) - that's pretty clever :D Thank's alot – Johannes Staehlin Mar 01 '12 at 06:08
  • ok - one more question :) Very easy to make an php-implementation. But what's about ajax? I see two problems: 1. Where do I store my token? (local var? cookie?) 2. The algorithm of the hash(token+A+B+C) will be available for everyone. (no one ca read my php-files, but the can read js-files) – Johannes Staehlin Mar 01 '12 at 08:19
  • Anything client-side is insecure, period. It doesn't matter if someone is reading the algorithm, that's not the important part. The algorithm is only designed to minimize risks of sending any sort of authentication over a network, the algorithm is not the secret. The secret is the token. And yes, you'll have to store the token somewhere on the client. And yes, that's ***always*** the biggest problem in security. The client has to have the token/password/keyphrase/whatever-other-secret, and the client is at the same time out of your hands entirely. – deceze Mar 01 '12 at 08:24
  • @deceze Hi, what is the benefit of creating tokens over just hashing the username password? tnx – Spring Dec 22 '12 at 12:27
  • 2
    @Spring More flexibility. Each client can get a unique token and these tokens can individually be revoked if need be. It also does not require the client to store sensitive information at all, only a meaningless token which could become invalid at any time. – deceze Dec 22 '12 at 15:46
  • @deceze Thank you, could you explain how server will create the hash again without server and client sharing a secret key? It can use a timestamp but same hash can be created by anyone who intercepted the request. And if assume it will not be intercepted(SSL) then there is no reason for all this security? – Spring Dec 26 '12 at 23:54
  • @@deceze another thing is in your example client puts the timestamp "into" hash so how server knows the correct timestamp to re-generate the hash? thanks – Spring Dec 26 '12 at 23:57
  • 3
    @Spring The `Token` is the shared secret key. The hash cannot be *recreated* by anyone except if that someone known the shared secret. Someone may be able to *reuse* the same token to repeat the same request, that's true. The server can filter such identical requests, if that seems like suspicious activity. The date used in the hash needs to be send as HTTP `Date` header (or similar). SSL indeed makes most of this redundant security, but more security is hardly bad, especially if it's just a simple yet effective hashing algorithm. – deceze Dec 27 '12 at 09:06
  • @deceze tnx could you have a look at my question, very appreciated http://stackoverflow.com/questions/14041496/rest-token-authentication-with-http-header – Spring Dec 27 '12 at 09:16
2

Here's a question about token-based authentication. I think the most common token-based authentication today is OAuth. But to answer your questions:

On a GET: Is the token send visible? (isn't that unsafe?)

You can pass your tokens through HTTP headers so they are not so easily seen. OAuth allows this. Note that the tokens are still visible, they're just not in the GET query parameters.

How do I make the token only valid for a specific time?

Since you control (create) the tokens, you can set expiry dates for each token. On every request of your API, you should just check your token storage (e.g. Database) if the given token is still valid. If it is not, then you can abort the request (maybe return a HTTP 401 error).

Community
  • 1
  • 1
Shiki
  • 16,688
  • 7
  • 32
  • 33
1

You can use fire-base php JWT (JSON Web Token) for token based authentication.

1)Install php jwt by running composer command composer require firebase/php-jwt

   require_once('vendor/autoload.php');
   use \Firebase\JWT\JWT; 
   define('SECRET_KEY','Your-Secret-Key')  // secret key can be a random string  and keep in secret from anyone
   define('ALGORITHM','HS512')

After that Generate your token

$tokenId    = base64_encode(mcrypt_create_iv(32));
                $issuedAt   = time();
                $notBefore  = $issuedAt + 10;  //Adding 10 seconds
                $expire     = $notBefore + 7200; // Adding 60 seconds
                $serverName = 'http://localhost/php-json/'; /// set your domain name 


                /*
                 * Create the token as an array
                 */
                $data = [
                    'iat'  => $issuedAt,         // Issued at: time when the token was generated
                    'jti'  => $tokenId,          // Json Token Id: an unique identifier for the token
                    'iss'  => $serverName,       // Issuer
                    'nbf'  => $notBefore,        // Not before
                    'exp'  => $expire,           // Expire
                    'data' => [                  // Data related to the logged user you can set your required data
                'id'   => "set your current logged user-id", // id from the users table
                 'name' => "logged user name", //  name
                              ]
                ];
              $secretKey = base64_decode(SECRET_KEY);
              /// Here we will transform this array into JWT:
              $jwt = JWT::encode(
                        $data, //Data to be encoded in the JWT
                        $secretKey, // The signing key
                         ALGORITHM 
                       ); 
             $unencodedArray = ['jwt' => $jwt];

provide this token to your user "$jwt" . On each request user need to send token value with each request to validate user.

 try {
           $secretKey = base64_decode(SECRET_KEY); 
           $DecodedDataArray = JWT::decode($_REQUEST['tokVal'], $secretKey, array(ALGORITHM));

           echo  "{'status' : 'success' ,'data':".json_encode($DecodedDataArray)." }";die();

           } catch (Exception $e) {
            echo "{'status' : 'fail' ,'msg':'Unauthorized'}";die();
           }

You can get step by step full configurations for php token based authentication

Zedd Index
  • 344
  • 2
  • 11