Can anybody help me with Ionic2 LinkedIn authentication without using ionic services, stamplay or AuthO, I have written the code, configured the app on linkedin, but it seems there is a problem with it(configuration) as the LinkedIn Popup opens but doesn't generates any response after entering credentials.
Note : I have used stamplay for linkdin
// install cordova-plugin-inappbrowser
declare var window: any;
export class HomePage {
constructor(public platform: Platform,private http: Http) {
this.platform = platform;
this.http = http;
}
linkedlogin()
{
this.platform.ready().then(() => {
this.linked().then(success => {
//Generate to the access token
let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
let options = new RequestOptions({ headers: headers });
this.http.get("https://www.linkedin.com/oauth/v2/accessToken?client_id='Your clientID'&client_secret='your client_secret'&redirect_uri=https://ionic-li-login.stamplayapp.com/auth/v1/linkedin/connect&code="+ success + "&grant_type=authorization_code",
options).map( res =>res.json()).subscribe(data =>
{
var accessToken = data.access_token;
//Get to the people data for login user data
this.http.get("https://api.linkedin.com/v1/people/~:(id,first-name,last-name,email-address,industry,picture-url,headline,date-of-birth,location:(name))?format=json&oauth2_access_token=" + accessToken )
.map( res =>res.json())
.subscribe(showdata => {
var linkdata = {
id:showdata.id,
firstName:showdata.firstName,
lastName:showdata.lastName,
emailAddress:showdata.emailAddress,
industry:showdata.industry,
headline:showdata.headline,
location:showdata.location.name,
pictureUrl:showdata.pictureUrl,
}
console.log(JSON.stringify(linkdata));
});
});
}, (error) => {
alert('Error');
});
});
}
linked(): Promise<any>
{
return new Promise(function(resolve,reject)
{
/* Linkedin login and signup page */
var browserRef = window.cordova.InAppBrowser.open("https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id='your clientID'&redirect_uri=https://ionic-li-login.stamplayapp.com/auth/v1/linkedin/connect&scope=r_basicprofile+r_emailaddress");
browserRef.addEventListener("loadstart", (event) => {
if ((event.url).indexOf("https://ionic-li-login.stamplayapp.com/auth/v1/linkedin/connect") === 0)
{
browserRef.removeEventListener("exit", (event) => {});
browserRef.close();
/* Will be generate to the authentication code */
var authcode = (event.url).split("code=")[1];
if(authcode !=null)
{
resolve(authcode);
}
else
{
alert("Problem authenticating with Linkdin");
}
}
});
browserRef.addEventListener("exit", function(event)
{
reject("The Linkdin sign in flow was canceled");
});
});
}
}
Related
I'm trying to implement a refresh token with Vue 3 and Java for backend. It is working but interceptor keeps firing.
The logic: On every request there's a JWT Authorization header that authenticates the user. If that expires, there's a cookie endpoint in place ready to refresh the JWT.
I am using axios and interceptor response to check if the client gets a 401 to try and refresh the JWT. The cookie may be valid or not.
The problem is that the interceptor to refresh the JWT never stops firing, and I think I have something wrong with the synchronization of the requests. Below is my code:
Api.js:
import axios from "axios";
const instance = axios.create({
baseURL: "MY_URL",
});
export default instance;
token.service.js:
class TokenService {
getLocalRefreshToken() {
const user = JSON.parse(localStorage.getItem("user"));
return user?.refreshToken;
}
getLocalAccessToken() {
const user = JSON.parse(localStorage.getItem("user"));
return user?.accessToken;
}
updateLocalAccessToken(token) {
let user = JSON.parse(localStorage.getItem("user"));
user.accessToken = token;
localStorage.setItem("user", JSON.stringify(user));
}
getUser() {
return JSON.parse(localStorage.getItem("user"));
}
setUser(user) {
// eslint-disable-next-line no-console
console.log(JSON.stringify(user));
localStorage.setItem("user", JSON.stringify(user));
}
removeUser() {
localStorage.removeItem("user");
}
}
export default new TokenService();
setupInterceptors.js:
import axiosInstance from "./api";
import TokenService from "./token.service";
const setup = (store) => {
axiosInstance.interceptors.request.use(
(config) => {
const token = TokenService.getLocalAccessToken();
if (token) {
config.headers["Authorization"] = 'Bearer ' + token;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
axiosInstance.interceptors.response.eject()
axiosInstance.interceptors.response.use(
(res) => {
return res;
},
async (err) => {
const originalConfig = err.config;
if (originalConfig.url !== "/auth/login" && err.response) {
// Access Token was expired
if (err.response.status === 401 && !originalConfig._retry) {
originalConfig._retry = true;
try {
const rs = await axiosInstance.post("/auth/refreshtoken", {
refreshToken: TokenService.getLocalRefreshToken(),
});
const { accessToken } = rs.data;
store.dispatch("auth/refreshToken", accessToken);
TokenService.updateLocalAccessToken(accessToken);
return axiosInstance(originalConfig);
} catch (_error) {
return Promise.reject(_error);
}
}
}
return Promise.reject(err);
}
);
};
export default setup;
try this out and make sure you use another instance of Axios for the refresh token request
// to be used by the interceprot
firstAxiosInstance = axios.create({ baseURL: MY_URL });
//to be used by the refresh token API call
const secondAxiosInstance = axios.create({ baseURL: MY_URL});
firstAxiosInstance.interceptors.response.use(
(res) => {
return res;
},
async (err) => {
// this is the original request that failed
const originalConfig = err.config;
// decoding the refresh token at this point to get its expiry time
const decoded = jwt.decode(localStorage.getItem('refreshToken'));
// check if the refresh token has expired upon which logout user
if (decoded.exp < Date.now() / 1000) {
store.commit('logout');
router.push('/');
}
// get new access token and resend request if refresh token is valid
if (decoded.exp > Date.now() / 1000) {
if (err.response.status === 401) {
originalConfig._retry = true;
try {
const rs = await requestService.post('/api-v1/token/refresh/', {
refresh: localStorage.getItem('refreshToken'),
});
store.commit('update_aceess_token', rs.data);
err.config.headers.Authorization = `Bearer ${rs.data.access}`;
return new Promise((resolve, reject) => {
requestService
.request(originalConfig)
.then((response) => {
resolve(response);
})
.catch((e) => {
reject(e);
});
});
} catch (_error) {
return Promise.reject(_error);
}
}
}
return Promise.reject(err);
},
);
try clean el token authorization before send request refresh, by example
in mutations(vuex)
clearAccessToken(state) {
state.access_token = ''
TokenService.removeAccessTokenApi();
},
For me it was fixed by not using the same axios instance for the refresh token request.
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']);
}
});
I have a main component with 2 sub-components (update, profile).
On update component, I have a form with several input fields. When I submit a form, profile section information should update after a successful request.
The problem is, profile information doesn't update after a successful request.
So, how to invoke profile component to refresh updated data? I tried to call a service after successful request, but no luck.
By the way, parent service looks like:
#Injectable()
export class AvailabilityService {
constructor(private http: Http) {
}
getProfile() {
return this.http.get(API_URL + '/user/profile')
.map(this.extractData)
.catch(this.handleError);
}
freeOwnersParking(availableDates: AvailableDates) {
let domain = API_URL + '/parking/availability';
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
let body = JSON.stringify(availableDates);
return this.http.put(domain, body, options)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body;
}
private handleError(error: any) {
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
return Observable.throw(errMsg);
}
}
UPDATE
Get profile:
getProfile() {
this.availabilityService.getProfile()
.subscribe(
profile =>this.profile = profile,
error => this.errorMessage = <any>error
);
}
Update profile:
freeOwnersParking() {
this.availabilityService.freeOwnersParking(this.availableDates)
.subscribe(
response => this.availabilityService.getProfile(),
error => this.errorMessage = error
);
}
You need to leverage a shared service between them to notify the profile component.
For example an UpdateProfileService with an observable / subject in it. In this case, the profile component can subscribe on it to be notified.
Here is the service:
#Injectable()
export class UpdateProfileService {
profileUpdated:Subject<boolean> = new Subject();
(...)
updateProfile(profile:any) {
return this.http.put('http://...', profile)
.map(res => {
this.profileUpdated.next(true);
return res.json();
});
}
}
and within the profile component:
#Component({
(...)
})
export class ProfileComponent {
constructor(private service:UpdateProfileService) {
this.service.profileUpdated.subscribe(() => {
// Update bound data for profile
});
}
}
I'm integrating Stripe payments with Angular2 (actually Ionic but the code is the same)
the call to Stripe.card.createToken is successful and returns a token
but in stripeResponseHandler which is an async callback, I cannot access any of the "this" variables. for example I cannot set this.amount = 10 and I cannot call this._http.post
how can I access the "this" variables ? I'm trying to http post the token and the amount to an API to make the payment
constructor(private _navController: NavController,
private _http: Http) { }
submitPayment() {
Stripe.setPublishableKey(this.key);
this.card = new Card();
this.card.number = this.cardNumber;
this.card.cvc = this.cardCVC;
this.card.exp_month = this.cardExpMonth;
this.card.exp_year = this.cardExpYear;
this.card.address_zip = this.cardAddressZip;
try {
Stripe.card.createToken(this.card, this.stripeResponseHandler);
}
catch (e) {
alert(e.message);
}
// Prevent the form from being submitted:
return false;
}
stripeResponseHandler(status, response) {
if (response.error) { // Problem!
alert(response.error);
} else { // Token was created!
// Get the token ID:
alert(response.id);
try {
this.amount = 10;
let payment = new Payment();
payment.token = response.id;
payment.amount = this.amount;
let body = JSON.stringify(payment);
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
this._http.post(this.url, body, options)
.map(res => res.json())
.catch(this.handleError);
}
catch (e) {
alert(e.message);
}
}
}
handleError(error: Response) {
// may send the error to some remote logging infrastructure
// instead of just logging it to the console
console.error(error);
alert('error' + error.text + " " + error.statusText);
return Observable.throw(error.json().error || 'Server error');
}
If you just pass the function reference, then JavaScript doesn't keep the this reference. You have to take care of this explicitely:
Instead of
Stripe.card.createToken(this.card, this.stripeResponseHandler);
use
Stripe.card.createToken(this.card, (status, person) => this.stripeResponseHandler(status, person));
See also https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions
or
Stripe.card.createToken(this.card, this.stripeResponseHandler.bind(this));
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();
}