Token authentication - where to store the token - php

I am working with PHP and Laravel at the moment, I have a restful api that the user needs to authenticate with to make sure they can only access things they own etc.
What I want to know is where should the token from the server be saved on the client? In a session a cookie? The servers database?

I suggest to go the following route:
the user logs into your site and requests a API usage token
when a new request to your API comes in, compare the token from the incomming request, with the token in the db. if it is found, it's a valid request. the REST client could use the Authorization header to send the token.
send the answer for the request
While the login system of your website, might be session-based with cookies on client-side, the REST API is token-based and doesn't need a cookie or session.
Please take a look at this for more details:
https://softwareengineering.stackexchange.com/a/141434/111803

Related

Obtaining Authorization Token From A Website API In PHP

I am working on a project which I need to integrate an api. The API's website requires that every request to their API be authorized by an Authorization token.
My problem is how to save the Authorization token safely and regenerate the token after expiration, so that the users of my website are able to use the Access token for their requests.
The token expires in 2 hours
Below is my request to obtain authorization token and the response.
response = unirest.post("https://webapisite.com/merchant/access",
headers={ "Accept": "application/json" },
params={ "apiKey": "my_api_key, "secret": "my_secret" });
I will receive below json response
{
"status": "success",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTQwLCJuYW1lIjoic2F2YW5hIHNtYXJ0c2F2ZSIsImFjY291bnROdW1iZXIiOiIiLCJiYW5rQ29kZSI6Ijk5OSIsImlzQWN0aXZlIjp0cnVlLCJjcmVhdGVkQXQiOiIyMDE2LTEyLTA4VDEwOjM4OjE5LjAwMFoiLCJ1cGRhdGVkQXQiOiIyMDE3LTA2LTE0VDEzOjAxOjQ5LjAwMFoiLCJkZWxldGVkQXQiOm51bGwsImlhdCI6MTQ5ODMzNTE2NSwiZXhwIjoxNDk4MzQyMzY1fQ.WojvkYOC2j6XTUfg_E4WQkxQChPUyCgYUCIKaW83YXA", // a valid merchant token
"config":{}
}
Perhaps the most commonly used standard for use cases like this is OAuth 2.0.
OAuth is a widely-recognized protocol on top of HTTP that is used to issue tokens to clients after successful authentication (see also: "What is the difference between authentication and authorization?" on ServerFault). It provides different "flows" to obtain the tokens by, the most suitable in your case would probably be the "Resource Owner Password Credentials Grant" flow. Clients can then use the tokens given to them to make the actual API request.
Storing the tokens is usually done in a database. In truly stateless applications, JSON Web Tokens can eliminate the need to store tokens on the server-side.
Its always better to save Token in DB and stored in session too.
With every request you can get token from session and track session activity by DB stored session.
Basically this kind of things part project flow, so according to project need and flow with aspect of security we can take decesion.
You should save this token in DB.
In one table, save the access token, auth token and expire date.
You can save multiple records if you want, but if you have only one auth token, one record is enough.
Before every call to that API, you check in the DB if the available access token is still valid, if it's not, you must renew the access token through the auth token.
I couldn't understand which language are you using to this task.
If javascript, you can make a post for your backend, asking for the latest valid token.
Hope that helps.

laravel 5.3 passport and angular storing access tokens

I am authenticating users to consume my own API (so a trusted source). What I am struggling to identify is where is the best place to store the return access_token on the client side? Do I create a cookie, or save the data in localstorage?
Also should I only store the access_token, I should I record the refresh_token? What is the refresh token used for?
It is safer if you only store the access token on the client side even if your refresh token expires after a certain period of time although doing this decreases the possible attack window.
This is one way of doing it (if you want to store access & refresh tokens):
https://stackoverflow.com/a/18392908/5549377
However there is another way of doing it.
In this way, the client will only get the access token and refresh token is completely hidden from the user. But inorder to do this, the access token as well as the refresh token should be stored in the server side. The best place is in the database. This raises the obvious question: security? Well the answer to that is you can always encrypt the data that is being store in the database and secure your database as much as possible.
Create a table (user_token table) that can store the user_id, access token, refresh_token and even the session_id.
In every login check if a record is existing under the user_id in the user_token table. If it does not exist, request the oauth/token and store the access and the refresh token in the user_token table.
After the login is successful, you can write a .run function in your angular to request for the access token for the user. (remember in the user_token table we had a "user_id" column. Hence you can request filter the current logged in user from the Auth::id() function in laravel.
Once the access token is found, the server should return the access token and access token only to the client.
After the client received the access token, you can do a handshake call to the route which is protected under 'middleware' => 'auth:api' by adding the recieved access_token to the header like this :$http.defaults.headers.common.Authorization = 'Bearer ' + data.access_token;. Also after doing that make sure you add the same token to the a rootscope variable like this:$rootScope.accesstoken = data.access_token;
If the handshake call is successful, then you can add valid access token from the rootscope to an angular cookie like this : $cookies.put('access_token', $rootScope.accesstoken);
If the handshake call is not successful, you can request a new token. To request a new token, use a new route that will redirect to a seperate function. This function will fetch the refresh token under the user_id of the current user and request a new access token from the oAuth end point (refer Passport API docs). Once you do this update the record under the user in the 'user_tokens' table and return the new access token to the web client. On the webclient side, store the recieved token in the angular cookie like this: $cookies.put('access_token', $rootScope.accesstoken); and add that same token to the http headers liek this: $http.defaults.headers.common.Authorization = 'Bearer ' + data.access_token;
By the way why did I mention that I should store the token in the angular cookie. Well if you store it only on the rootscope, if the page refreshes, the app will have to request for a token again because whatever the data in the angular rootscope is lost after refresh. But in the angular cookie, it is not. hence this is why I suggested to add to the angular cookie.
Very important:
For every ajax request you make, if the request fails under the code 401 (unauthorized access), you should call a request new token function from angular to Laravel's request new token function. And once it is successful, insert that new token to the http header and the angular cookie as I mentioned.
Note:
The point of the refresh token is to verify that you are the authenticated user for the old access token (let's call the token xxx).
You can use the access token as long as it expires. Once it does you need to tell the server that you cannot been using this access_token xxx and it is expired now, so give me a new token. When you make this request (to give you a new token) the server should know you are the legitimate user of the previous access token, so the server will ask you to prove that you are legitimate. At that time, you can to present the refresh token and prove the server that you are legitimate. This is the use of the refresh token.
So how will the server verify you are legitimate by the refresh token?
initially when you requested the access token, you are given the refresh token so in that case the server will know.
I suggest you read and learn more on OAuth 2.0.
I recently went through some client-side options for token storage so I'll refer you the answer provided in: Where to save a JWT in a browser-based application.
Long story short, both cookies and Web storage are suitable options for storing access tokens and the right choice depends on your exact scenario.
In relation to what you should store, it's usually just the access token mostly because refresh tokens are not typically issued to browser-based applications because they are long-lived credentials meaning the time available for someone trying to steal them is highly increased and the browser storage options all have their deficiencies.
The refresh token is also of particular interest when a client application wants to have access to a protected resourced owned by the end-user even when the user is not interacting with the application; usually referred to as offline access. Most scenarios for browser based applications still imply that the user is online so lack of refresh tokens is not that a big of a deal.

Simple token-like authentication

Does the following authentication system seem reasonable:
Client calls the login end point with a user name and password to the main server. The main server sends this off to another authentication server (which will receive no further mention), which returns a yes/no if this is valid and a user ID that the main server is aware of. If yes, generate a random token (using some crypto library that spits out random strings), and store the hash of this (using PHP's password_hash()) and an expiry 12 hours from now on the user record. Return the token to the client.
Client now adds "Authorization: Token TOKEN+HERE+ABCD1234" to their requests to other endpoints. The server ensures that the hash of the token in the auth header matches the one in the database (using salts through PHP's password_verify()), and that the expiry hasn't been hit. If it doesn't match, or the expiry is exceeded, then send back a 401.
Seems at least as secure as basic HTTP authentication, which just has the base-64 encoded user:password in the header? The reason I'm considering this scheme over basic is that the main server won't store the username/password that the authentication server is using to log in.
What am I forgetting? Is this grossly insecure?
Your scheme is not that different from the standard server-side sessions where SESSION-ID is normally nothing more than a random token and stored on the client side within a cookie, with 2 improvements:
Instead of a cookie you would use Authorization header to deliver the token. This acts as a CSRF protection.
You would hash a token on the server-side. This helps against session hijacking in case someone gets access to your token-store on the server-side.
If you see the oAuth process of Google then you will get idea of how Authorization works for them.
They have different servers for Authorization and API calls. User sends authentication details to Authorization server and receive a code. Google is having process of taking user consent to access details but you can skip this process to take consent and just return code on successful details.
This code can be further used to get the Access Token from the API server. So your first request to API server would be to get the Access Token. Google is having facility to refresh your Access Token as well.
And all subsequent request to API server must contain Access Token. So you seems to be missing this Code exchange process to make it more secure.
More info: https://developers.google.com/identity/protocols/OAuth2

PHP Console Application with OAuth 2.0 Refresh Tokens, how to store?

I am working on a PHP project that utilizes the API from a few services. For a single API, it uses OAuth 2.0 authorization to authenticate the application's API access. However, I am unsure how I should approach the process to authenticate a local console application.
I would not be using a webflow to authenticate the API, as my PHP script runs in a local console. The API allows for the retrieving of the access token and refresh token by entering my username and password (they recommend this only for console applications).
Once I get the access token, I may use it to make API requests. This works fine. However, I am unsure what to do with my refresh token. The API consumes refresh tokens as such:
/oauth2/access_token/ (Refresh token usage)
Context: Client's Web Server
Required arguments: refresh_token, grant_type=refresh_token,
client_id, client_secret
Access token scope: None
On success, a JSON response is returned to the client:
{
"access_token": a valid access token,
"scope": scope as given in authorize,
"expires_in": seconds to expiry,
"refresh_token": a token that can be used to get a new access token
}
Consuming a refresh token will immediately expire the related access
token. Refresh tokens are single-use. A new refresh token is returned
from this call, ready for consumption later.
From what I gather from this, my authentication process should be something like this:
Initial authentication - pass username/password via environment variable, get the access/refresh token from response
Store the refresh token? Check for the expiry of the initial access token
If initial access token has expired, pull refresh token from file and make a request for a new access/refresh token
Store new refresh token?
Does this sound like the correct authentication flow? Is there a specific way I should be storing the refresh token? I am aware there may be a lot of security concerns for simply storing the refresh token in a text file, as it has the ability to give complete access to my account. Are there any better alternatives?
Thanks!
Authentication flow is fine. For more detailing and validation, you can read https://www.rfc-editor.org/rfc/rfc6749 .
You can store ‘Refresh token’ either in file or db using encryption key and this MUST only be transmitted using TLS. ‘Refresh token’ is used in senerios where server do want to some scheduled background activities like accessing of profile and related data from other oAuth server based on previous stored access token without asking user name and password again over and again. If in case ‘Access token’ is invalidated then ‘Refresh token’ will be used to get new ‘Access token’ to serve purpose.

Google API Authentication for server

I've been trying to get Google's Calendar API working in a PHP web application, but I'm having a hard time getting authenticated.
What I want to do is to allow users to interact with calendars of a single account known by the server.
Each type of scenario covered in the OAuth 2.0 docs talks about "user consent" which involves a login form and the individual user logging in, but I want the server itself to authenticate directly and obtain an access token for itself.
Is there some part of OAuth or some alternative mechanism I can use to do this?
In order to do this, you must go through the steps for user consent and then copy the access tokens it gives you into the PHP code.
The usual procedure for OAuth is like this:
Send user to authentication page.
User comes back with $_GET['code']
Send $_GET['code'] to OAuth server for a token
Store token in database for the user (or session, if it's very short lived)
But when doing it with a single calendar like this, you modify step 4. Instead, you dump the token to screen and copy it into your PHP file as variables, instead of putting it in the database. Then when you go to pass the access token to the server, you just pass the known, static token rather than a dynamic token from the database / session.
See mathewh's answer here:
How to automate login to Google API to get OAuth 2.0 token to access known user account
The lightbulb for me is when you get the access token you get a refresh_token as well... you use this token to "refresh" your access token once it expires.
There is no way around a manual authorization step the first time.

Categories