Authorization permissions - loopback

I use ra-loopback. And I want to add a role during authorization. I tried to add a role like this:
./authClient.js
import storage from './storage';
import {decode} from 'jsonwebtoken';
export const authClient = (loginApiUrl, noAccessPage = '/login') => {
return (type, params) => {
if (type === 'AUTH_LOGIN') {
const request = new Request(loginApiUrl, {
method: 'POST',
body: JSON.stringify(params),
headers: new Headers({ 'Content-Type': 'application/json' }),
});
return fetch(request)
.then(response => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
})
.then(({token}) => {
const decoded = decode(token);
storage.save('lbtoken',token);
storage.save('role', decoded.role);
});
}
if (type === 'AUTH_LOGOUT') {
storage.remove('lbtoken');
return Promise.resolve();
}
if (type === 'AUTH_ERROR') {
const status = params.message.status;
if (status === 401 || status === 403) {
storage.remove('lbtoken');
return Promise.reject();
}
return Promise.resolve();
}
if (type === 'AUTH_CHECK') {
const token = storage.load('lbtoken');
if (token && token.id) {
return Promise.resolve();
} else {
storage.remove('lbtoken');
return Promise.reject({ redirectTo: noAccessPage });
}
}
if (type === 'AUTH_GET_PERMISSIONS') {
const role = localStorage.getItem('role');
return role ? Promise.resolve(role) : Promise.reject();
}
return Promise.reject('Unknown method');
};
};
When i tried to login, i get an error 'Cannot read property 'role' of null'.
Actually, i want to add permissions to Admin.
I want some resources to be visible only to admin. I know how it does, but I don`t know how to add role to user during authorization.

try this:
import storage from './storage';
import {
decode
} from 'jsonwebtoken';
export const authClient = (loginApiUrl, noAccessPage = '/login') => {
return (type, params) => {
if (type === 'AUTH_LOGIN') {
const request = new Request(loginApiUrl, {
method: 'POST',
body: JSON.stringify(params),
headers: new Headers({
'Content-Type': 'application/json'
}),
});
return fetch(request)
.then(response => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
})
.then(({
token
}) => {
const decoded = decode(token);
storage.save('lbtoken', token);
storage.save('role', decoded.role);
});
}
if (type === 'AUTH_LOGOUT') {
storage.remove('lbtoken');
storage.remove('role');
return Promise.resolve();
}
if (type === 'AUTH_ERROR') {
const status = params.message.status;
if (status === 401 || status === 403) {
storage.remove('lbtoken');
storage.remove('role');
return Promise.reject();
}
return Promise.resolve();
}
if (type === 'AUTH_CHECK') {
const token = storage.load('lbtoken');
if (token && token.id) {
return Promise.resolve();
} else {
storage.remove('lbtoken');
storage.remove('role');
return Promise.reject({
redirectTo: noAccessPage
});
}
}
if (type === 'AUTH_GET_PERMISSIONS') {
const role = localStorage.getItem('role');
if (role) {
return Promise.resolve(role);
} else {
storage.remove('lbtoken');
storage.remove('role');
return Promise.reject({
redirectTo: noAccessPage
});
}
}
return Promise.reject('Unknown method');
};
};

Related

React Query always returning isError as False

We are using Axios along with react query. Can someone point me to correct example, so that all the react query keys like isError, isSuccess is properly set. As, I read through other answers, the catch block below might be the culprit.
function api<TResponse>({
method,
url,
body,
contentType = 'application/json',
}: IAccessInterceptor): Promise<TResponse> {
return new Promise((resolve, reject) => {
const payload: AxiosRequestConfig = {
method,
url,
headers: {
Accept: contentType,
'content-type': contentType,
},
};
// including 'data' if body is not null
if (body != null) {
payload.data = body;
}
axios(payload)
.then((response: { data: { message: TResponse; data: TResponse } }) => {
resolve(response.data?.message || response.data?.data);
})
.catch((error: { response: { data: IServerError } }) => {
reject(error?.response?.data);
});
});
}
// Some problem in above catch block.
const getABC = (
id: string,
): Promise<IABC> => {
const method = 'GET';
const url = `${BASE_URL}.get_abc?assignment_id=${assignmentId}`;
return api<IABC>({ method, url });
};
export const useABC = (
assignmentId: string | null,
): UseQueryResult<IABC> =>
useQuery<IABC, Error>(
queryKeys.getABC(id),
() => someFunction(id|| ''),
{ enabled: !!id},
);
"useABC().isError" is always false

the tokenGetter method does not wait for the promise to be completed before attempting to process the token

I am using Jwt tokens for authentication and using a interceptor for adding access token to the requests.I have a getToken() method which is checking for token's validity and calling the service for getting new set of tokens. The method is returning promise but the requests are taking the promise before it gets completed and failing to get the updated token.
Below is my code:
export class TokenService {
refresh = false;
constructor(public injector: Injector) {
}
public getToken(): string | Promise<string> {
const jwtHelper = new JwtHelperService();
let token = localStorage.getItem('token');
let refreshToken = localStorage.getItem('refreshToken');
if (!token || !refreshToken) {
return null;
}
if (jwtHelper.isTokenExpired(token)) {
if (jwtHelper.isTokenExpired(refreshToken)) {
return null;
} else {
let tokenPromise;
if (!this.refresh) {
this.refresh = true;
tokenPromise = this.promiseFromObservable(this.getTokenService(localStorage.getItem('refreshToken')));
}
return tokenPromise;
}
} else {
return token;
}
}
getTokenService(refreshToken: string) {
let http = this.injector.get(HttpClient);
const httpOptions = {
headers: new HttpHeaders({
'Authorization': 'Bearer ' + refreshToken
})
};
return http.post<Tokens>(location.origin + '/LiveTime/services/v1/auth/tokens?locale=en', null, httpOptions);
}
promiseFromObservable(o): Promise<string> {
return new Promise((resolve, reject) => o.subscribe((token: Tokens) => resolve(token.token),reject(), err => { console.log(err); return null; }))
.then((token: Tokens) => {
localStorage.setItem('token', token.token);
localStorage.setItem('refreshToken', token.refreshToken);
this.refresh = false;
return token.token;
},
err => { console.log(err); return null; }
)
.catch((error) => { console.log(error);reject();
});
}
}
Can someone tell me what is wrong in this code?

Ionic2 - http get is not working

I have written a authentication service to authenticate user name and password in a Login Page. The code below is the service.
public login(credentials) {
if (credentials.username === null || credentials.password === null) {
return Observable.throw("Please insert credentials");
} else {
let apiURL = 'http://localhost/timeclock/api/login?usercode=' + credentials.username +
'&password=' + credentials.password ;
return Observable.create(observer => {
this.http.get(apiURL).map(res => res.json()).subscribe(data => {
if (data.success === 'true')
{
this.currentUser.name = data.data.user_name;
this.currentUser.email = data.data.user_email;
observer.next(true);
observer.complete();
} else {
observer.next(false);
observer.complete();
}
});
});
}
}
When the user name and password is submitted, the URL is correctly called with the right parameters.
The http call takes very long time to complete. Also, no response is returned.
It takes only two or three seconds to get the response when I call the URL with the same parameters in the browser.
Any idea on how to fix this?
You don't need to create a new Observable you can refactor like this.
public login(credentials) : Observable<boolean> {
if (credentials.username === null || credentials.password === null) {
return Observable.throw("Please insert credentials");
} else {
let apiURL = 'http://localhost/timeclock/api/login?usercode=' + credentials.username +
'&password=' + credentials.password ;
return this.http.get(apiURL).map(res => res.json())
.map(data =>
{
if(data.success){
this.currentUser.name = data.data.user_name;
this.currentUser.email = data.data.user_email;
return true;
}else{
return false;
}
});
}
}

Append firebase JWT in Ember-simple-auth

I am trying to do authorization in my Ember App(2.10). My workflow is
user hit the button of Facebook login then
i'm using torii to get the access token /my user database is on firebase/
Then i send token to firebase.auth with facebook provider. It returns JWT token.
Problem is i got the JWT token and now i have to login to my emberapp. I am trying to customize torii authenticator here. How can i implement this in ember app. Below is my authenticator:
authenticate() {
return this._super(...arguments).then((torii) => {
const serverTokenEndpoint = this.get('serverTokenEndpoint');
return this.get('ajax').request(serverTokenEndpoint, {
type: 'POST',
data: {
'type': torii.provider,
'client_id': this.client,
'token': torii.authorizationCode
}
}).then((token) => {
var provider = new firebase.auth.FacebookAuthProvider();
firebase.auth().signInWithPopup(provider).then(function(result) {
// This gives Facebook Access Token.
// JWT-token=result.user.Cd
// JWT-token.iat at=result.user.ea.Sa
// JWT-token-refresh = result.user.refreshToken
console.log(result)
// token = result.user.Cd;
// const expiresAt = this._absolutizeExpirationTime(result.user.ea.Sa);
token = Ember.assign(token, { 'expires_at': result.user.ea.Sa });
// this._scheduleAccessTokenRefresh(result.user.ea.Sa, expiresAt, result.user.refreshToken, torii);
return Ember.assign(token, {'torii': torii});
});
});
});
}
Check out this guide in the ESA repo. It covers torii and Github auth but the general concepts are the same for your use case.
#marcoow I did try this and it authenticate but when token is expired i can not refresh token.Seems it is not the right approach, How can i refresh token using firebase
export default ToriiAuthenticator.extend({
torii: Ember.inject.service(),
ajax: Ember.inject.service(),
refreshAccessTokens: true,
rejectWithResponse: false,
restore(data) {
return new RSVP.Promise((resolve, reject) => {
const now = (new Date()).getTime();
const refreshAccessTokens = this.get('refreshAccessTokens');
if (!isEmpty(data['expires_at']) && data['expires_at'] < now) {
// if (refreshAccessTokens) {
this._refreshAccessToken(data['expires_in'], data['refresh_token']).then(() => {
resolve();
}).catch(function(error) {
reject();
});
// } else {
// reject();
// }
} else {
if (!this._validate(data)) {
reject();
} else {
this._scheduleAccessTokenRefresh(data['expires_in'], data['expires_at'], data['refresh_token']);
resolve(data);
}
}
});
},
authenticate() {
return new Ember.RSVP.Promise((resolve, reject) => {
var provider = new firebase.auth.FacebookAuthProvider();
firebase.auth().signInWithPopup(provider).then((result) => {
var expires_in = this._absolutizeExpirationTime(result.user.ea.Sa);
var expiresAt = result.user.ea.Sa;
result = Ember.assign(result, { 'expires_at': expiresAt, 'expires_in': expires_in, 'access_token': result.user.Cd, 'refresh_token': result.refresh_token });
resolve(result)
});
// const useResponse = this.get('rejectWithResponse');
// const provider = new firebase.auth.FacebookAuthProvider();
// firebase.auth().signInWithPopup(provider).then((result) => {
// let expires_in = result.user.ea.Sa;
// const expiresAt = this._absolutizeExpirationTime(expires_in);
// this._scheduleAccessTokenRefresh(expires_in, expiresAt, result.refresh_token);
// if (!isEmpty(expiresAt)) {
// result = Ember.assign(result, { 'expires_at': expiresAt, 'expires_in': expires_in, 'access_token': result.user.Cd, 'refresh_token': result.refresh_token });
// }
// // resolve(result);
// }, (response) => {
// Ember.run(null, reject, useResponse ? response : response.responseJSON);
// }).catch(function(error) {
// console.log(error);
// });
});
},
invalidate(data) {
const serverTokenRevocationEndpoint = this.get('serverTokenRevocationEndpoint');
return new RSVP.Promise((resolve) => {
if (isEmpty(serverTokenRevocationEndpoint)) {
resolve();
} else {
if (!Ember.isEmpty(data.access_token)) {
delete data.access_token;
firebase.auth().signOut();
resolve();
}
}
});
},
_scheduleAccessTokenRefresh(expiresIn, expiresAt, refreshToken) {
console.log('sched')
const refreshAccessTokens = this.get('_refreshAccessTokens');
if (refreshAccessTokens) {
const now = (new Date()).getTime();
if (isEmpty(expiresAt) && !isEmpty(expiresIn)) {
expiresAt = new Date(now + expiresIn * 1000).getTime();
}
const offset = this.get('tokenRefreshOffset');
if (!isEmpty(refreshToken) && !isEmpty(expiresAt) && expiresAt > now - offset) {
run.cancel(this._refreshTokenTimeout);
delete this._refreshTokenTimeout;
if (!testing) {
this._refreshTokenTimeout = run.later(this, this._refreshAccessToken, expiresIn, refreshToken, expiresAt - now - offset);
}
}
}
},
_refreshAccessToken(expiresIn, refreshToken) {
console.log('refresh');
const data = { 'grant_type': 'refresh_token', 'refresh_token': refreshToken };
firebase.auth().currentUser.getToken(/ forceRefresh / true).then((response) => {
return new RSVP.Promise((resolve, reject) => {
// firebase.auth().currentUser.getToken(true).then((response) => {
expiresIn = response.user.ea.Sa || expiresIn;
refreshToken = response.refresh_token || refreshToken;
const expiresAt = this._absolutizeExpirationTime(expiresIn);
const data = assign(response, { 'expires_in': expiresIn, 'expires_at': expiresAt, 'refresh_token': refreshToken });
this._scheduleAccessTokenRefresh(expiresIn, null, refreshToken);
this.trigger('sessionDataUpdated', data);
resolve(data);
}, (response) => {
warn(`Access token could not be refreshed - server responded with ${response.responseJSON}.`);
reject();
});
});
},
_absolutizeExpirationTime(expiresIn) {
if (!isEmpty(expiresIn)) {
return new Date((new Date().getTime()) + expiresIn * 1000).getTime();
}
},
_validate(data) {
return !isEmpty(data['access_token']);
}
});

react-native-fbsdk - how to get user profile?

onLoginFinished's result just tells me the granted permissions. From the repo, not clear how to get the user profile. Seems like react-native-fbsdkcore should wrap FBSDKProfile.h but don't see where it does.
var FBSDKLogin = require('react-native-fbsdklogin');
var {
FBSDKLoginButton,
} = FBSDKLogin;
var Login = React.createClass({
render: function() {
return (
<View>
<FBSDKLoginButton
onLoginFinished={(error, result) => {
if (error) {
alert('Error logging in.');
} else {
if (result.isCanceled) {
alert('Login cancelled.');
} else {
alert('Logged in.');
}
}
}}
onLogoutFinished={() => alert('Logged out.')}
readPermissions={[]}
publishPermissions={['publish_actions']}/>
</View>
);
}
});
Found out you can get logged in user's profile with Graph API.
// Create a graph request asking for user's profile
var fetchProfileRequest = new FBSDKGraphRequest((error, result) => {
if (error) {
alert('Error making request.');
} else {
// Data from request is in result
}
}, '/me');
// Start the graph request.
fetchProfileRequest.start();
There is an easier way to do it. Rather than manually making the graph request yourself, 'react-native-fbsdkcore' package to get the data associated with the logged in user (if there is one)
var
FBSDKCore = require('react-native-fbsdkcore');
var {
FBSDKAccessToken,
} = FBSDKCore;
FBSDKAccessToken.getCurrentAccessToken((token) => {
// token will be null if no user is logged in,
// or will contain the data associated with the logged in user
});
cphackm address is that in this issue #2
Using #flow, here is a full example:
FbLogin.js
// #flow
import * as React from 'react';
import { View } from 'react-native';
import { LoginButton, AccessToken } from 'react-native-fbsdk';
import { FbService } from '#services';
import { toast } from '#libs/helpers';
type LoginResult = {
isCancelled: boolean,
grantedPermissions?: Array<string>,
declinedPermissions?: Array<string>
};
type Props = {
store: {
Account: Object
}
};
type State = {
token?: string
};
export default class Login extends React.Component<Props, State> {
componentDidMount() {
AccessToken.getCurrentAccessToken().then(tokenData => {
if (tokenData) {
console.log('[-- tokenData --]', tokenData);
const { accessToken, userID } = tokenData;
if (accessToken) {
console.log('[-- accessToken, userID --]', accessToken, userID);
this.setState({ token: accessToken });
// this._getUserInformation();
}
}
});
}
_getUserInformation = () => {
const { token } = this.state;
const { Account } = this.props.store;
if (token) {
FbService.getFbUserData(token, (error, result) => {
if (error) {
console.log('[-- error --]', error);
} else {
Account.provider = 'facebook';
Account.authorized = true;
Account.current = { password: '', token, ...result };
console.log('[-- responseFbUserData --]', result);
}
});
}
};
render() {
return (
<View>
<LoginButton
readPermissions={['public_profile']}
onLoginFinished={(error: Object, result: LoginResult) => {
if (error) {
alert('Login failed with error: ' + error.toString());
} else if (result.isCancelled) {
alert('Login was cancelled');
} else {
if (result) {
this._getUserInformation();
}
}
}}
onLogoutFinished={() => toast('User logged out', 'info')}
/>
</View>
);
}
}
/* AccessToken
accessToken: string,
applicationID: string,
userID: string,
permissions: Array<string>,
declinedPermissions: Array<string>,
accessTokenSource?: string,
expirationTime: number,
lastRefreshTime: number,
*/
FbService.js
// #flow
import * as React from 'react';
import { GraphRequestManager, GraphRequest, AccessToken } from 'react-native-fbsdk';
export function getFbUserData(token: string, callBack: Function) {
const profileRequestConfig = {
httpMethod: 'GET',
version: 'v2.12',
parameters: {
fields: {
string: 'id, name, email'
}
},
accessToken: token
};
const profileRequest = new GraphRequest('/me', profileRequestConfig, callBack);
new GraphRequestManager().addRequest(profileRequest).start();
}