Trying to integrate APIs built in Laravel 5.4 with ionic 2 and struggling handle the error
What I want to do:
Authenticate the login using Laravel Password service ( OAuth2 ).
Once authenticated, it would return the access token.
Access Token is passed in the header in a GET API call to receive the
user details.
I am able to #1 and #2 but got stuck at #3.
Here is my code of login.ts
public login() {
this.showLoading();
this.auth.login(this.loginCredentials).subscribe(allowed => {
if (allowed) {
setTimeout(() => {
this.loading.dismiss();
this.nav.setRoot(HelloIonicPage)
});
} else {
this.showError("Access Denied");
}
},
error => {
this.showError(error);
});
}
auth is a service provider, that has login method.
//Function to get access token
public login(credentials) {
if (credentials.email === null || credentials.password === null) {
return Observable.throw("Please insert credentials");
} else {
return Observable.create(observer => {
var link = 'http://localhost/XXX/public/oauth/token';
var vars = {
password: "XXX",
username: "XXXXXX",
grant_type: 'password',
client_id: "XXXXX",
client_secret: 'XXXXXX',
scope: ''
}
this.http.post(link, vars)
.map(res => res.json())
.subscribe(
data => { let user = this.getUserFromAccessToken(data);
console.log(user);
observer.next(user);
},
err => { observer.error(err.json()); }
() => {
console.log('Completed..');
}
);
});
}
}
//Function to get user from the accessToken
private getUserFromAccessToken(oAuthData) {
let headers = new Headers({ 'Content-Type': 'application/json','Accept': 'application/json','Authorization': 'Bearer ' + oAuthData.access_token });
let options = new RequestOptions({ headers: headers });
let link = 'http://localhost/XXXX/public/api/v1/user';
return this.http.get(link, options)
.map(res => res.json())
.subscribe(
data => this.currentUser = data.user,
err => this.error = err
);
}
currentUser and error are defined as properties of the AuthService class.
How should I ensure that an error is thrown either in case the access token is not returned or user is not returned from the access token.
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 using Laravel apis for my project. The API is working fine when I use curl to access it.
curl -H "Content-Type: application/json" -X POST -d '{"username":"xyz","password":"xyz", "filterZip":"123123"}' http://localhost:8080/api/signup {"error":{"message":"User with specified email address already started sign up process, but did not finished it. Please sign in regulary to continue sign up process.","errorCode":"020102"}}
However when I call if from nodejs app. I am unable to access the error Json Object from the response.
From Nodejs I am calling my laravel API
fetch(API_URI + '/signup', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
}).then(checkResponse)
.then(response => {
userData = response.data;
req.session.user = {
username: userData.displayName || userData.email,
data: userData,
auth: authData
};
req.session.resession = true; // tell ssrCache to act
return res.status(200).json(req.session);
})
.catch(status,error) => {
console.log('Request failed', error);
req.session.user = null;
req.session.resession = true; // tell ssrCache to act
return res.status(200).json(req.session);
});
});
const checkResponse = (response) => {
if (response.status >= 200 && response.status < 300) {
return response.json();
}
var error = new Error(response);
error.code = object.error.errorCode;
throw error;
}
On the Laravel API end following code is used to return response.
public function respondError($errorId, $statusCode, $message = 'Unknown') {
$this->setHttpStatusCode($statusCode);
$errorCode = ErrorHelper::generateErrorCode($this->controllerErrorId, $this->methodErrorId, $errorId);
if (API_LOG_ERROR_CODES) { ErrorHelper::logErrorCode($errorCode, $message); }
return $this->respond([
'error' => [
'message' => $message,
'errorCode' => $errorCode
]
]);
}
public function respond($dataForJson, $headers = []) {
return response()->json($dataForJson, $this->getHttpStatusCode(), $headers);
}
OK I figured it out.
The issue was with my handling of response. In the response I was not converting the response to response.json() whenever the response.status was greater than 300. once I did that I was able to extract the required json object. Following is a better approach for handling response.
const checkResponse = (response) => {
if (response.status >= 200 && response.status < 300) {
return response.json();
}
return reject(response.status, response.json());
}
I am currently a beginner of react native and I want to know if I wanted to login and store user data using AsyncStorage, what key and value should be passed?
AsyncStorage.setItem('key', 'value');
UserLogin = () =>{
const { username } = this.state ;
fetch('https://www.example.com/React/user-login.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: username,
})
}).then((response) => response.json())
.then((responseJson) => {
// If server response message same as Data Matched
if(responseJson === 'Data Matched')
{
login(username, password).then(authenticationToken => {
AsyncStorage.setItem('token', authenticationToken)
})
//Then open Profile activity and send user email to profile activity.
this.props.navigation.navigate('ProfileScreen', { username:username });
}
else{
Alert.alert(responseJson);
}
}).catch((error) => {
console.error(error);
});
}
If I were to say if logged in, then AsyncStorage.setItem('key', 'value');, then that could work if I want to store say the user's username so that I can display it on their profile page?
AsyncStorage parameters are both strings, so you can store serialised json data or just a plain string.
// Some code that logs someone in and gets an authentication token which then is stored
login(username, password).then(authenticationToken => {
AsyncStorage.setItem('token', authenticationToken)
})
// then somewhere else in your code
AsyncStorage.getItem('token').then(authenticationToken => {
console.log(‘the token’, authenticationToken)
})