I am building an api authentication with laravel for a React frontend.
The problem is when I do a post with Insomnia to /auth I get the response correctly. But when I do it with axios in React... the response returns null.
LARAVEL
public function store(AuthRequest $request)
{
$credentials = $this->authService->getCredentials($request->all());
if (!$token = auth('api')->attempt($credentials)) {
return $this->errorResponse("Unauthorized", 401);
}
$tokenData = $this->authService->getTokenData($token);
return response()->json($tokenData);
}
REACT
export function* signIn({ payload }) {
const { email, password } = payload;
const response = yield call(api.post, 'auth', {
email,
password,
});
console.tron.log(response);
const { token, user } = response.data;
yield put(signInSuccess(token, user));
history.push('home');
}
INSOMNIA
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODAwMFwvYXBpXC9hdXRoIiwiaWF0IjoxNTc2NTg0Nzc1LCJleHAiOjE1NzY1ODgzNzUsIm5iZiI6MTU3NjU4NDc3NSwianRpIjoiSGlnZlNvcVN1OWZaU3AwUyIsInN1YiI6MSwicHJ2IjoiMjNiZDVjODk0OWY2MDBhZGIzOWU3MDFjNDAwODcyZGI3YTU5NzZmNyJ9.SK4c2sm7mVnmZVAqkujYhcPWDHKzmGUjUNzoOsQx7eg",
"token_type": "bearer",
"expires_in": 3600
}
AXIOS
data:""
status:200
statusText:OK
headers:
url:http://localhost:8000/api/auth
method:post
data:{"email":"admin#admin.com","password":"321321"}
baseURL:http://localhost:8000/api
timeout:0
adapter: xhrAdapter()
xsrfCookieName:XSRF-TOKEN
xsrfHeaderName:X-XSRF-TOKEN
maxContentLength:-1
validateStatus: validateStatus()
request:{}
Does anyone can help me??
Related
I keep getting 404 error when I try to submit the form even though the routes are correctly placed in api.php.Can somebody please help??
const url = "/api/add-feedback";
const token = process.env.MIX_REACT_APP_API_TOKEN;
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [review, setReview] = useState("");
const handleSubmit = async (e) => {
e.preventDefault();
const data = {
name: name,
email: email,
review: review
}
const res = await axios.post(url, data, {
headers: {
Authorization: "Bearer " + token,
},
});
if (res.data.status === 200) {
console.log(res.data.message);
}
}
Here is the route in api.php
Route::post('/add-feedback',[ApiController::class,'feedback']);
Here is the ApiController function
public function feedback(Request $res)
{
$data = $res->validate([
'name'=>'required',
'email'=>'required|email',
'review'=>'required'
]);
Feedback::create($data);
return response()->json([
'status' => 200,
'message' => 'Feedback Added Successfully'
]);
}
This is the error I get:
app.js:3415 POST http://127.0.0.1:8000/api/add-feedback 404 (Not Found)
app.js:3880 Uncaught (in promise) Error: Request failed with status code 404
The error is you're using promises with axios, modify your code to something like this:
axios.post(url, data,{
headers: {
Authorization: "Bearer " + token,
},
})
.then((response) => {
if (res.data.status === 200) {
console.log(res.data.message);
}
}, (error) => {
console.log(error);
});
This will send a post request to your route with the data specified.
I've been hitting wall for a while now with this, simply I can't get it where is the problem. So I've got backend Laravel and front Vue; logging in is alright, I get token but when I get into one of the routes with auth:api I get "message":"Unauthenticated.". I save token on the front, so should I send it with any request to backend or there is other way around it?
LoginController.php
public function login(Request $request)
{
$login = $request->validate([
'email' => 'required',
'password' => 'required',
]);
if(Auth::attempt($login))
{
return response(['message' => 'Invalid login']);
}
$user = User::where('email', $request->email)->first();
$accessToken = $user->createToken('Laravel Password Grant Client')->accessToken;
return response()->json(['user' => $user, 'access_token' => $accessToken]);
}
api.php
Route::namespace('\\')->middleware('auth:api')->group(function(){
Route::resource('budget', BudgetController::class);
});
user.js
const state = {
token: localStorage.getItem('access_token') || null,
isAuthenticated: localStorage.getItem('access_token') !== null
}
const getters = {
isAuthenticated: state => state.isAuthenticated
}
const actions = {
async retrieveToken({commit}, payload){
console.log(payload)
const response = axios.post(url + '/login', payload)
.then(response => {
const token = response.data.access_token
localStorage.setItem('access_token', token)
commit('setToken', token)
})
}
}
const mutations = {
setToken: (token) => state.token = token
}
Alright, so simply in my second module I used token as a header like this:
const state = {
budget: [],
header: {
headers: {
Authorization: `Bearer ${localStorage.getItem("access_token") || null}`,
withCredentials: true,
"Access-Control-Allow-Origin": "*"
},
}
};
const getters = {
allBudget: (state) => state.budget,
};
const actions = {
async fetchBudget({ commit, state }) {
const response = await axios.get(url, state.header);
console.log(state.header);
commit("setBudget", response.data);
},
};
After that I was getting CORS error so i needed to add two directives at the end of the file xampp\apache\conf\httpd.conf
Header Set Access-Control-Allow-Origin *
Header Set Access-Control-Allow-Headers *
I'm having issues with my application, I used php-jwt JSON Web Token Authentication in my angular 9 apps and the token works fine when I'm not redirecting to successful page after login. when redirecting to the dashboard after login the token is set and immediately remove from localStorage. How can I allow token even after redirection to new page? Any help will be highly appreciated.
My auth.service.ts file
// Sign-in
signIn(user: Usermodule) {
return this.http
.post<any>(`${this.endpoint}/signin.php`, user)
.subscribe((res: any) => {
localStorage.setItem('ACCESS_TOKEN', res.jwt);
this.getUserProfile(res.id).subscribe((res) => {
this.router.navigate(['app/dashboard']);
});
});
}
// User profile
getUserProfile(id): Observable<any> {
let api = `${this.endpoint}/user_profile.php`;
return this.http.get(api, { headers: this.headers }).pipe(
map((res: Response) => {
return res || {};
}),
catchError(this.handleError)
);
}
auth.interceptors.ts file
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(request: HttpRequest<any>, next: HttpHandler) {
const access_Token = this.authService.getToken();
request = request.clone({
setHeaders: {
Authorization: 'Bearer ' + access_Token,
},
});
return next.handle(request);
}
}
app.module.ts file
JwtModule.forRoot({
config: {
tokenGetter: () => {
return localStorage.getItem('ACCESS_TOKEN');
}
// whitelistedDomains: ['localhost'],
// blacklistedRoutes: ['localhost/auth/login']
}
})
],
providers: [
AuthService,
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi:true}
],
bootstrap: [AppComponent]
Once I comment out //this.router.navigate(['app/dashboard']); the token stays in localstorage without been killed and I can even access restricted area when I type the address manually.
I am posting data to Laravel and expect a success response, but it catches the exception TypeError: Network request failed. Using get methods and login post methods using Laravel passport works all fine.
Adding 'Content-Type': 'application/json' to headers creates Network request failed for the login methods.
Postman returns valid errors or success, so works totally as expected.
Debugging showed that the request has been sent to Laravel and routing is correct as Visual Studio Code debugger stops at a breakpoint at return response.
public function postMessages()
{
...
return response()->json(['success' => 'success'], 200);
}
Route::middleware('auth:api')->group(function () {
Route::post('messages', 'Api\ChatController#postMessages');
});
export const fetchApi = async (endPoint, method = 'get', body = {}) => {
const accessToken = authSelectors.get().tokens.access.value;
const accessType = authSelectors.get().tokens.access.type;
let headers = {
...(accessToken &&
{
Authorization: `${accessType} ${accessToken}`
}
)
};
let response;
if (method=='get' || Object.keys(body)==0 ) {
response = await fetch(`${apiConfig.url}${endPoint}`, {
method: method,
headers: headers
});
} else {
var formData = new FormData();
Object.keys(body).forEach(type => {
formData.append(type, body[type]);
});
response = await fetch(`${apiConfig.url}${endPoint}`, {
method: method,
headers: headers,
body: formData
});
console.log('fetch response: ' + JSON.stringify(response));
}
let responseJsonData = await response.json();
return responseJsonData;
}
export const postMessages = (eidug, type, name, messages) => fetchApi('/message', 'post', {
'eidug': eidug,
'type': type,
'name': name,
'messages': messages
});
I expect a response without any exception like Postman. What can be going wrong?
Have you enabled CORS in the backend? Once open inspect->network and then run fetch. Show if there are any errors.
I am building an API for a Laravel 5 Web application using AngularJs App as API consumer.
Everything works perfectly except for the response returned from the API when a call is made from AngularJS.
Here is what I have in AngularJs App which also uses Satellizer
var app = angular
.module('app', [
'ngResource',
'ui.bootstrap',
'dialogs.main',
'ui.router',
'satellizer',
'ui.router.stateHelper',
'templates'
]);
app.config(['$httpProvider', '$locationProvider', '$stateProvider', '$urlRouterProvider', 'modalStateProvider', '$authProvider',
function($httpProvider, $locationProvider, $stateProvider, $urlRouterProvider, modalStateProvider, $authProvider)
{
var modalInstance,
modalExit = function() {
if (modalInstance) {
//alert('modalInstance exit');
modalInstance.close();
}
};
// Satellizer configuration that specifies which API
// route the JWT should be retrieved from
$authProvider.loginUrl = '/api/authenticate';
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
$stateProvider
.state('profile',{
url: '/profile',
views: {
'contentFullRow': {
templateUrl: 'ng/templates/profile/partials/profile-heading-one.html',
controller: function($scope, profile){
$scope.profile = profile;
}
},
'contentLeft': {
templateUrl: 'ng/templates/profile/partials/profile-body-one.html',
controller: function($scope, profile){
$scope.profile = profile;
}
},
'sidebarRight': {
templateUrl: 'ng/templates/profile/partials/todo-list-one.html',
controller: function($scope, profile){
$scope.profile = profile;
}
}
},
resolve: {
profile: function($http){
return $http.get('/api/profile').then(function(data){
//This is the issue, I am doing this because of the response returned
return data.data.profile;
});
}
}
});
if(window.history && window.history.pushState){
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
};
}]);
In my Laravel Controller
<?php namespace App\Http\Controllers\Profile;
use App\Http\Controllers\Controller;
use App\Models\Profile;
class ProfileController extends Controller
{
public function __construct()
{
$this->middleware('api.auth');
}
public function getIndex(){
$user = $this->auth->user();
return Profile::find($user->id);
}
}
Response from Laravel
The challenge I have is in the response above.
As you can see in the resolve method of Angular Ui Router,
To get the profile object from the returned JSON, I had to do this:
return $http.get('/api/profile').then(function(data){
return data.data.profile;
});
How do I make the API to return only profile object without config, header and other objects sent along? Are they really necessary? I would like to simply do this:
return $http.get('/api/profile').then(function(data){
return data; //which contains only profile object
});
Edited:
I think my question is; Is this the right JSON response Format from Dingo Api?
{
"config",
"data": {
"id": 1001,
"name": "Wing"
},
"headers",
"status",
"statusText"
}
Have you tried to return a response from the controller, not an Eloquent object:
http://laravel.com/docs/master/responses.
You can specify what exactly you need there (like profile).