I am trying to set up Torii with my own OAuth flow and Ember-Simple-Auth. I can get a successful authentication event, but immediately after I authenticate, the invalidateSession trigger is fired causing my session to end. I can see this by intercepting sessionInvalidated() in /app/routes/application.js (which has the ApplicationRouteMixin).
Have any of you come across this? Is there something peculiar that would cause an immediate session validation? Any advice would be greatly appreciated.
EDIT: I think it has to do with the torii popup code because the first return works, but the second doesn't. Any thoughts?
import OAuth2 from 'torii/providers/oauth2-code';
import {configurable} from 'torii/configuration';
export default OAuth2.extend({
name: 'api',
init() { this.set('clientID', this.get('apiKey')); },
baseUrl: configurable('baseUrl'),
redirectUri: configurable('redirectUri'),
responseParams: ['access_token', 'user_id', 'first_name'],
requiredUrlParams: ['client_id', 'redirect_uri', 'response_type'],
open() {
let name = this.get('name');
let url = this.buildUrl();
let redirectUri = this.get('redirectUri');
let responseParams = this.get('responseParams');
// this return works
return { 'yes' : 'no' }
// this return causes the immediate invalidation
return this.get('popup').open(url, responseParams).then((authData) => {
var missingResponseParams = [];
responseParams.forEach(function(param){
if (authData[param] === undefined) {
missingResponseParams.push(param);
}
});
if (missingResponseParams.length){
throw new Error("The response from the provider is missing " +
"these required response params: " + missingResponseParams.join(', '));
}
return {
access_token: authData.access_token,
first_name: authData.first_name,
user_id: authData.user_id,
provider: name,
redirectUri: redirectUri
};
});
}
});
the real answer is using this fork: https://github.com/simplabs/ember-simple-auth/pull/931 (hopefully it'll be in master soon).
You might have this.get('session').invalidate(); somewhere. Probably in one of your controllers action properties. You would usually put that in your actions for your logout button. Maybe you copy and pasted it by accident. If you post some code I might be able to look at it some more
Related
I m new to loopback and don't know how to do following things in loopback
I want to set access token and other value in a session using middleware for that I found this thing in server folder of loopback
"session": {},
in middleware.json but don't know how to use this because there is not much documentation
I want to condition in session middleware like if I has session value then continue else throw to login page
note i already install this npm install express-session
Could you be a little more specific about what you want? but I'll explain a little bit about how authentification sessions are handled, there are two native ways you treat it all; The first one would be using a more raw reading pulling for modeling of your api and the second would be to use the JWT in aligned with accessToken and Passport.JS.
There are two examples available today with Loopback 3.x
loopback-example-user-management
loopback-example-passport
Basically using the raw reading with app.post('/login', function(req, res) then if your client is successfully authenticated you generate a cookie using your client's accessToken, example res.cookie('access_token', token.id, { signed: true , maxAge: 300000 }); res.set('X-Access-Token', token.id); and finally if you want you can transport the generated token to your pages:
res.render('home', {
email: req.body.email,
accessToken: token.id
});
Now with Passport.JS a middleware is used to secure all your connection and authentication:
app.middleware('session:before', cookieParser(app.get('cookieSecret')));
app.middleware('session', session({
secret: 'Seal Playing Saxophone',
saveUninitialized: true,
resave: true,
}));
passportConfigurator.init();
One of the authenticated page rendering pillar is var ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn; you can use this ensureLoggedIn('/login') to free up your routes:
app.get('/auth/account', ensureLoggedIn('/login'), function(req, res, next) {
res.render('pages/loginProfiles', {
user: req.user,
url: req.url,
});
});
Now if you just want to skip this all and already have your environment set up and just want to create a route to get the accessToken of the logged in client use the template below;
app.get('/session-details', function (req, res) {
var AccessToken = app.models.AccessToken;
AccessToken.findForRequest(req, {}, function (aux, accesstoken) {
// console.log(aux, accesstoken);
if (accesstoken == undefined) {
res.status(401);
res.send({
'Error': 'Unauthorized',
'Message': 'You need to be authenticated to access this endpoint'
});
} else {
var UserModel = app.models.user;
UserModel.findById(accesstoken.userId, function (err, user) {
// show current user logged in your console
console.log(user);
// setup http response
res.status(200);
// if you want to check the json in real time in the browser
res.json(user);
});
}
});
});
I hope I have illuminated your ideas :] I am here to answer your questions.
I am using ember-simple-auth and ember-cli-facebook-js-sdk.I am using the ember-cli-facebook-sdk because I want to get the user photo anytime as facebook only give the access which expires in 60 mins.So I can't save also.Ember-cli-facebook-sdk is working fine.But sometimes I am getting an error in my network console.
{"error":{"message":"An active access token must be used to query information about the current user.","type":"OAuthException"}
I am not able to think why this error is coming.I have a initializer which have facebook id and api version.And Now I am using Fb.api and others in my controller,component and other.But it fails sometimes.Please anwser where I am going wrong.Thanks in advance.
initializer/fb.js
import FB from 'ember-cli-facebook-js-sdk/fb';
export default {
name: 'fb',
initialize: function() {
return FB.init({
appId: '1234567',
version: 'v2.3',
xfbml: true
});
}
};
controller.js
usrphoto:Ember.computed('model',function(){
var currentState = this;
FB.api('/me/picture','Get',{'type':'large'}).then(function(response) {
currentState.set('usrphoto', response.data.url)
})
}
I think what happens here is, that your Facebook session expires. In that case you need to handle the error and manage it. For example, you could check for a valid session and in case the session is expired, require a new token and then do your request:
FB.getLoginStatus().then(function(response) {
if (response.status === 'connected') {
return Ember.RSVP.resolve();
} else {
return FB.login('email,user_photos'); //set your scope as needed here
}
}).then(function() {
return FB.api('/me/picture','Get',{'type':'large'});
}).then(function(response) {
currentState.set('usrphoto', response.data.url);
});
Another possibility is to handle the error in the catch of the FB.api:
FB.api('/me/picture','Get',{'type':'large'}).then(function(response) {
currentStatte.set('userphoto', response.data.url);
}).catch(function(reason) {
...handle your error here...
});
I've been working all week to get authentication working. I have gotten it working with
Ember-CLI
Ember-Simple-Auth
Torii
google-oauth2 provider
However I have proven unsuccessful in getting the users information from google. I have tried creating a torii-adapter as stated in their documentation but it doesn't appear to be called
// app/torii-adapters/application.js
export default Ember.Object.extend({
open: function(authorization){
console.log('authorization from adapter', authorization);
}
});
I've exhausted my google-foo and am asking for your assistance. This is a great library combination for authorization however the documentation is lacking for this case, and when figured out I will be sure to contribute back.
Thank you
The problem I was encountering is Torii's default google-oauth2 provider doesn't access this info for you, also it uses the code workflow instead of the token workflow which is needed for the google+ API
To fix this I wrote a custom provider that uses a jquery GET request to the G+ API, I then return the userName and userEmail to access it in the session under content.
I wrote a full tutorial detailing authorizing an ember app using google start to finish here
//app/torii-providers/google-token.js
import {configurable} from 'torii/configuration';
import Oauth2Bearer from 'torii/providers/oauth2-bearer';
var GoogleToken = Oauth2Bearer.extend({
name: 'google-token',
baseUrl: 'https://accounts.google.com/o/oauth2/auth',
// additional params that this provider requires
requiredUrlParams: ['state'],
optionalUrlParams: ['scope', 'request_visible_actions', 'access_type'],
requestVisibleActions: configurable('requestVisibleActions', ''),
accessType: configurable('accessType', ''),
responseParams: ['token'],
scope: configurable('scope', 'email'),
state: configurable('state', 'STATE'),
redirectUri: configurable('redirectUri',
'http://localhost:8000/oauth2callback'),
open: function(){
var name = this.get('name'),
url = this.buildUrl(),
redirectUri = this.get('redirectUri'),
responseParams = this.get('responseParams');
var client_id = this.get('client_id');
return this.get('popup').open(url, responseParams).then(function(authData){
var missingResponseParams = [];
responseParams.forEach(function(param){
if (authData[param] === undefined) {
missingResponseParams.push(param);
}
});
if (missingResponseParams.length){
throw "The response from the provider is missing " +
"these required response params: " + responseParams.join(', ');
}
return $.get("https://www.googleapis.com/plus/v1/people/me", {access_token: authData.token}).then(function(user){
return {
userName: user.displayName,
userEmail: user.emails[0].value,
provider: name,
redirectUri: redirectUri
};
});
});
}
});
export default GoogleToken;
Alright, this is my first question on SO so I'll try to make it a good one sorry ahead of time.
I've been using ember-cli to work on a product. I am using Firebase simple login for authentication and have created an initializer that adds an auth object to all my controllers and routes.
This works, but... There seems to be a delay for the redirect checking. example I go to /secret and this should redirect me back to the /login route and it does but there is a slight delay where I can see the template
I've tried to create a gist with all the necessary information. Let me know if there is anything else I can provide to help out
https://gist.github.com/mbertino/060e96e532f8ce05d2d0
You could provide a flag on your auth object, which you use in your route to conditionally display the content:
import Ember from 'ember';
var firebase = new window.Firebase( window.MyAppENV.APP.firebaseURL );
export default Ember.Object.extend({
authed: false,
init: function(route) {
var self = this;
self.authClient = new window.FirebaseSimpleLogin( firebase ), function(error, user) {
self.set( 'authed', false );
if (error) {
alert('Authentication failed: ' + error);
} else if (user) {
self.set( 'authed', true );
// if already a user redirect to the secret resource
route.transitionTo('secret')
} else if (route.routeName !== 'login'){
// if the route is anything but the login route and there is not
// a user then redirect to the login resource
route.transitionTo('login')
}
}.bind(this));
You then can use {{#if auth.authed}} in your templates to reveal private data, or display different content.
Instead of setting the flag above, I use a watcher on the authenticated status, this is provided by the API (documented here: https://www.firebase.com/docs/web/guide/user-auth.html#section-monitoring-authentication):
// also in init()
self.authRef = new window.Firebase( firebase + '/.info/authenticated' );
self.authRef.on( 'value', function( snap ) {
var oldAuthed = self.get('authed');
if ( snap.val() === true ) {
self.set( 'authed', true );
if ( ! oldAuthed ) {
// Status switched form unauthenticated to authenticated
// go to your route here
);
}
} else {
self.set( 'authed', false );
if ( oldAuthed ) {
// User was logged in, is now logged out
}
}
});
Keep in mind that it's JavaScript, and nothing you can do will be fool-proof. In other words, you can try to hide anything, but someone who really wants to can always hack into your data structures and reveal a hidden page that way. If you don't want people to see something, make sure they can't read it in the first place (by locking down access through the Firebase privilege system).
First of all I don't use Ruby nor Devise :) (all my searches led me to plugins that kind of rely on Devise)
I want to do pretty simple authentication with Ember, I have a REST backend that blocks requests without a proper cookie(user-pass) and i want Ember to watch when it gets 403 forbidden (won't let you to transition into protected URLs) and then pop up a user-login dialog.
So when a user tries to send a new message for example(lets say i've built a forum) Ember will fire the request and if it gets 403 it will block the transition and popup a login form and will retry the transition after the login have completed
Also is there a way to get the errors from ember-data and respond to them? (if a user tries to change an attribute he can't access i would like to inform him about it[Access denied or something like that])
I want to use custom errors that my server will send to ember data not just error numbers but words like "Sorry you can't change this before 12 PM"
You can simply listen to the response of your server and transition to your LOGIN (or whatever you call it) route. In my apps I happen to keep two types of routes (LOGIN and AUTHENTICATED). When they access the authenticated routes without logging in, they get a 401 unauthorized error and get transitioned to the LOGIN route.
// AuthenticatedRoute.js
redirectToLogin: function(transition) {
// alert('You must log in!');
var loginController = this.controllerFor('login');
loginController.set('attemptedTransition', transition);
this.transitionTo('login');
},
events: {
error: function(reason, transition) {
if (reason.status === 401) {
this.redirectToLogin(transition);
} else {
console.log(reason);
window.alert('Something went wrong');
}
}
},
model: function () {
return this.store.find('post');
},
So now when the user requests for post he gets a 401 and gets transitioned to LOGIN controller.
// LoginController.js
login: function() {
var self = this, data = this.getProperties('username', 'password');
// Clear out any error messages.
this.set('errorMessage', null);
$.post('/login', data).then(function(response) {
self.set('errorMessage', response.message);
if (response.success) {
alert('Login succeeded!');
// Redirecting to the actual route the user tried to access
var attemptedTransition = self.get('attemptedTransition');
if (attemptedTransition) {
attemptedTransition.retry();
self.set('attemptedTransition', null);
} else {
// Redirect to 'defaultRoute' by default.
self.transitionToRoute('defaultRoute');
}
}
});
}
The basic answer you need is capturing the events in the route and transitioning accordingly. I just happened to include the code for attempted transition as it comes in handy at times.