What is the best way to save token (JWT) in cakephp 4? - cakephp

I have a project and I made the backend using nodejs.
I made a user registration module and the authentication generates a token!
This token will need to be used in other requests where the user must be logged in.
What is the best way to store this token on the frontend using cakephp 4?
Is there any component? Is it safe to store this token using the session?
I would appreciate it if someone could help analyze this case.
This is my authentication method:
public function login()
{
$http = new Client();
if ($this->request->is('post')) {
$response = $http->post(
'http://localhost:8889/api/auth/login',
[
'email' => $this->request->getData("username"),
'password' => $this->request->getData("password"),
]
);
if ($response->getStatusCode() == 401) {
return $this->redirect($this->referer());
}
if ($response->isOk()) {
$json = $response->getJSON();
return $this->redirect(['action' => 'home', 'controller' => 'Pages']);
}
}
}
Return 200 contains an accessToken.

The best way to store the token is with an HttpOnly Cookie.
According to the Microsoft Developer Network, HttpOnly is an
additional flag included in a Set-Cookie HTTP response header. Using
the HttpOnly flag when generating a cookie helps mitigate the risk of
client-side script accessing the protected cookie (if the browser
supports it).
If you store it in a LocalStorage/SessionStorage then it can be easily grabbed by an XSS attack (from Javascript/Client side)
The CakePHP 4 way to do it is like this:
https://book.cakephp.org/4/en/controllers/request-response.html#creating-cookies
$cookie = new Cookie(
'jwt_token', // name
'token', // value
new DateTime('+1 hour'), // expiration time
'/', // path
'example.com', // domain
true, // secure only?
true // http only -> this is what you need
);

Related

laravel reactjs pusher: presence channel response is 302

I'm trying to make a reactjs application where an user can only login to one device at the time with the same user credentials. Unfortunately it isn't working.
I'm trying to authenticate a presence channel with reactjs to laravel but I get a 302 response.
reactjs:
Pusher.logToConsole = true;
var pusher = new Pusher("9028d58568392772df59", {
cluster: "eu",
forceTLS: true,
authEndpoint: '/broadcasting/auth',
auth: {
headers: {
'X-CSRF-Token': csrf_token
}
}
});
var channel = pusher.subscribe("presence-HandleCredentials");
channel.bind("sameCredentials", function(data) {
console.log(data);
alert(JSON.stringify(data));
});
channel:
Broadcast::channel('App.User', function ($user, $id = 1) {
return (int) $user->id === (int) $id;
});
broadcast:
public function boot()
{
Broadcast::routes(['middleware' => ['auth:web']]);
require base_path('routes/channels.php');
}
When I added this ['middleware' => ['auth:web']] I got the error. Before I added that I got a 403 error.
in the config\app.php I uncommented App\Providers\BroadcastServiceProvider::class,
Are there any tutorials out there that are build with laravel and reactjs for a presence channel?
does anyone know how to get past this 302 redirect?
Recently had the same issue with my laravel-websockets and laravel echo.
In my case I was unable to solve the 302, as Broadcast was unable to authenticate my logged in user. I was trying to subscribe to my private channel. So the workaround i found was that i manually created a POST route in web.php as "/broadcasting/auth". This is what my front-end requests to. So The updated code in web.php is as follows.
Route::post('/broadcasting/auth', function(Request $request){
$pusher = new Pusher\Pusher(
env('PUSHER_APP_KEY'),
env('PUSHER_APP_SECRET'),
env('PUSHER_APP_ID'),
array(
'cluster' => env('PUSHER_APP_CLUSTER'),
'useTLS' => false,
'host' => env('APP_URL'),
'port' => 6001,
'scheme' => 'http',
)
);
return $pusher->socket_auth($request->request->get('channel_name'),$request->request->get('socket_id'));
});
I was creating my own websocket that is why i had to mention the host & port within the options, you don't need to use it if you are Using Pusher. You can also add other middlewares to the routes if needed.
You have to comment out the following line in app/providers/BroadcastServiceProvider:
public function boot()
{
// Broadcast::routes();
require base_path('routes/channels.php');
}
so that the request can reach my broadcasting/auth route in web.php.
Try this. now this should return a 200 when the broadcasting/auth is requested by your client end with response of an auth code. Do let me know if this solves your problem.

where and how to store laravel passport authentication token and send request from front-end with that token?

i've created a laravel passport api based authentication.and using react js as frontend.when i send login request with email,password my backend send me authentication token.now where should i store this token?? if i want store it in cookies how to do that?? and how to send this with frontend ajax request??
actually i'm totally new.so if this question sound stupid ,i'm sorry..
this is my login function:
public function login()
{
if (Auth::attempt(['email' => request('email'), 'password' => request('password')])) {
$user = Auth::user();
$success['token'] = $user->createToken('AppName')->accessToken;
return response()->json(['success' => $success], $this->successStatus);
} else {
return response()->json(['error' => 'Unauthorised'], 401);
}
}
You can save the token to local Storage on react js.It is one of the method to store and access the token.
localStorage.setItem("token", token value)

How do I manage an access token, when storing in local storage is not an option?

I have a ReactJS app running in browser, which needs access to my backend laravel-passport API server. So, I am in control of all code on both client and server side, and can change it as I please.
In my react app, the user logs in with their username and password, and if this is successful, the app recieves a personal access token which grants access to the users data. If I store this token in local storage, the app can now access this users data by appending the token to outgoing requests.
But I do not want to save the access token in local storage, since this is not secure. How do I do this?
Here is what I have tried:
In the laravel passport documentation, there is a guide on how to automatically store the access token in a cookie. I believe this requires the app to be on the same origin, but I cannot get this to work. When testing locally, I run the app on localhost:4000, but the API is run on my-app.localhost. Could this be a reason why laravel passport does not make a cookie with the token, although they technically both have origin localhost?
OAuth has a page on where to store tokens. I tried the three options for "If backend is present", but they seem to focus on how the authorization flow rather than how to specifically store the token.
Here's the relevant parts of my code (of course, feel free to ask for more if needed):
From my react app:
const tokenData = await axios.post(this.props.backendUrl + '/api/loginToken', { email: 'myEmail', password: 'myPassword' })
console.log('token data: ', tokenData)
const personalAccessToken = tokenData.data.success.token;
var config = {
headers: {
'Authorization': "Bearer " + personalAccessToken
};
const user = await axios.get(this.props.backendUrl + '/api/user', config);
From the controller class ApiController:
public function loginToken()
{
if (Auth::attempt(['email' => request('email'), 'password' => request('password')])) {
$user = Auth::user();
$success['token'] = $user->createToken('MyApp')->accessToken;
return response()->json(['success' => $success], 200);
} else {
return response()->json(['error' => 'Unauthorised'], 401);
}
}
and the loginToken function is called from the /api/loginToken route.
Expected and actual results:
Ideally, I would love to have the token saved in a cookie like in the passport documentation, so I don't even have to attach the token to outgoing requests from the react app, but I'm not sure that this is even possible. Perhaps with third party cookies?
Else, I'd just like to find some way to store the token securely (for example in a cookie?), and then append it to outgoing calls from the react app.

How to get authenticated token inside already logged in page

I'm new to React. I have already set up small size web service with Django backend on AWS EB. It has custom user model. And most contents are available after user logged in. It works fine.
When I start to make a mobile app with React Native, I set up the Django Rest into same place with sharing same db models with web service. I have chosen a Token authentication way for it. It works fine with React Native app on mobile. Once users log in through a mobile app, API returns auth Token. After getting Token from API, mobile app interacts with API including Token in JSON header.
During learn and develop React Native mobile app. I enjoyed it very much. So, I want to put small react app into one of my web pages, not writing a whole single page app. At this stage, one problem came to my mind that how my react app gets auth Token without inputting user ID and password again.
I spent hours to find any clue through googling, but failed. Can anyone give me a hint? How react app inside already logged web page interact with Token auth based API without log in again?
I think you can use cookies or localStorage to save your token and then in react part just get this token out of there.
You can use localStorage to set and get the token
ex:
set - > localStorage.setItem('token', 'dac43hh5r3nd23i4hrwe3i2un32u');
get - > localStorage.getItem('token');
For ReactJS, take a look at Where to store token. You can use localStorage or cookies.
Cookie usage:
document.cookie = cookie_name + "=" + value + ";expires=" + expire_date + ";";
PS: The expire date should be on GMT format.
localStorage usage:
// To set the token
localStorage.setItem('token', 'dac43hh5r3nd23i4hrwe3i2un32u');
// To get the token
localStorage.getItem('token');
The Django docs for Session, and read this question, it would help you.
Cookie or localStorage?
I would take cookies. Why? Because you can set expiration date(for automatic deletion, for example), domain, path and other things that can be useful. On the localStorage, you just store the info.
I'd like to leave my answer after I solved in my way through my long research and study. My solution is quite simple.
1. set DRF session authentication enable. Adding some code in setting.py
REST_FRAMEWORK = {
# ...
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
}
2. add 'credentials: "include"' into fetch code to use already logged in session cookie for authentication.
await fetch(API_URL, {
credentials: "include"
})
this solution solved my case.
React you can use any libray for the calling API, ex- axios is one of them. When you do the login first time save that token in the localstorage or session.
Now we have to add that token in header for that you can user the interceptor i.e when we make API call every time interceptor will get call, at that place you can get the token from the local storage or session add the request header.
below is sample code of interceptor.
import axios from 'axios';
import cookie from 'react-cookies';
import * as utils from './utils';
let axios_instance = axios.create();
axios_instance.interceptors.request.use(
(configuration) => {
const config = configuration;
const authToken = cookie.load('authToken');
if (authToken) {
config.headers.Authorization = `Token ${authToken}`;
}
return config;
},
(error) => Promise.reject(error)
);
axios_instance.interceptors.response.use((response) => {
return response;
}, (error) => {
if (error.response.status == 401) {
utils.clearCookie();
window.location.href = '/login';
return;
}
if (error.response.status == 403) {
utils.clearCookie();
window.location.href = '/login';
return;
}
if (error.response.status == 404) {
// window.location.href = '/not-found';
return;
}
if (error.response.status == 500) {
// window.location.href = '/server-error';
return;
}
return Promise.reject(error);
});
export default axios_instance;

How to create Token-Based Authentication(oauth2) for AngularJS and Laravel Apps via passport

I created an web app which it uses laravel default registration(auth), I've tested passport oauth2 client access token from taylor tutorial. My web app uses angular js for UI and laravel for backend , so I need to create user, when create user request is sent from angular and then create a global access token to give it in my response to angular which then in all later request I use it to authenticate requests.
actually I want to implement oauth2 authentication for my web app, but so far I've searched a lot but I couldn't find any useful step by step tutorial for it.
anyone can help me out?
FYI: I'm using laravel 5.3 with passport enabled and angular js 1.5 for frontend.
Use JWT token based authentication here you can learn about jwt https://jwt.io/
I've solved this.
I've Customized laravel auth for login and register and created a method which will send a request to the server to create an access token for registering user or log in.
I've set up passport and test it as taylor did in his toturial.
then in AuthenticatesUsers.php I've changed sendloginResponse method response like :
protected function sendLoginResponse(Request $request)
{
isset($request->token) ? $token = $request->token : $token = null;//Check if login request contain token
$request->session()->regenerate();
$this->clearLoginAttempts($request);
return $this->authenticated($request, $this->guard()->user())
? $this->StatusCode($token,$this->credentials($request),$status=false) : $this->StatusCode($token,$this->credentials($request),$status=true);
}
And I have added this method to request access token and send it as json response :
public function StatusCode($token,$user,$status){
if( $token != null && $token != ''){
return ($status == true) ? response()->json(GetToken($user),200) : response()->json(['Message' => 'Failed to log in'],403);
}
function GetToken($userobject)
{
$http = new Client;
$response = $http->post('http://localhost/iranAd/public/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => '1',
'client_secret' => 'xKqNbzcXyjySg20nVuVLw5nk5PAMhFQOQwRTeTjd',
'username' => $userobject['email'],
'password' => $userobject['password'],
'scope' => '',
],
]);
return json_decode((string) $response->getBody(), true);
}
function RefreshToken($token,$userobject)
{
$http = new Client;
$response = $http->post('http://localhost/iranAd/public/oauth/token', [
'form_params' => [
'grant_type' => 'refresh_token',
'refresh_token' => 'refresh_token',
'client_id' => '1',
'client_secret' => 'xKqNbzcXyjySg20nVuVLw5nk5PAMhFQOQwRTeTjd',
'username' => $userobject['email'],
'password' => $userobject['password'],
'scope' => '',
],
]);
return json_decode((string) $response->getBody(), true);
}
return ($status == true) ? response()->json(GetToken($user),200) : response()->json(['Message' => 'Failed to log in'],403);
}
Same Procedure for register users.
The purpose of this post is not to answer(as already answered) but to give more info to other readers who eventually need more info on topic.
This is very helpfull tutorial just on this issue Implementing Vue.js 2.0 and Laravel 5.3 with CORS problem solution
Check this one and 2 next clips.
Some of this you can find in shorter form here here

Resources