ember-simple-auth is not saving auth response to session - ember.js

I'm using ember-simple-auth and I can see that the authentication token is returned and that my custom authenticator is putting it (code-wise) into the session.
I can use wireshark to see that the token comes back but I can't debug into the authenticator code - I can't even use debug statements as the redirect wipes the network session on google chrome.
However, it isn't in the session (google chrome tools) and the session isn't considered authenticated.
Why is the lock code correctly popping up the auth0 dialog but not saving the session? I don't really think it is something with this code but rather a config or initialization setting I'm unaware of.
I expect the session to be saved in the _setupFutureEvents as the first thing it does.
Any ideas what I can try to get it to work?
(/app/authenticators/lock.js) authenticate (options) {
return new Ember.RSVP.Promise((res) => {
this.get('lock').show(options, (err, profile, jwt, accessToken, state, refreshToken) => {
if (err) {
this.onAuthError(err);
} else {
var sessionData = { profile, jwt, accessToken, refreshToken };
// pass the NEW auth0 session data into future events
this.afterAuth(sessionData).then(response => res(this._setupFutureEvents(response)));
}
});
});
},
afterAuth (data) {
return Ember.RSVP.resolve(data);
},
_setupFutureEvents (data) {
// set the session info here
this.get('sessionData').setProperties(data);
this._clearJobs();
this._scheduleExpire();
if (this.get('hasRefreshToken')) {
this._scheduleRefresh();
}
return this.get('sessionData');
},

Related

Nuxt Vuex Helper not sending Client Cookies to API

Okay, I have the bad feeling that I'm missing a key concept in what I'm doing. Hope someone can help me out with a hint.
I'm using Nuxt and Vuex Store Modules. Every fetch a Module Action does is wrapped in a helper Function (saveFetch) that I imported to decrease repetitive code, like this:
export const actions = {
async sampleAction(context, data){
...
await saveFetch(context, 'POST', '/pages', data)
...
}
}
The helper simple checks if the users accessToken is still valid, refreshes it if not and then sends the request:
export const saveFetch = async (context, method = 'POST', path, data) => {
const accessTokenExpiry = context.rootGetters['auth/getAccessTokenExpiry']
let accessToken = context.rootGetters['auth/getAccessToken']
// If the client provides an accessToken and the accessToken is expired,
// refresh the token before making the "real" fetch.
if (accessToken && accessTokenExpiry < new Date() && path !== '/auth/refresh-token') {
if (process.client) {
// Works fine
await window.$nuxt.$store.dispatch('auth/refreshToken')
} else {
// This is where the trouble starts
await context.dispatch('auth/refreshToken', null, { root: true })
}
accessToken = rootGetters['auth/getAccessToken']
}
return fetch(path, {
method,
headers: { ... },
body: JSON.stringify(data),
}
}
If the accessToken is expired the helper function dispatches a Vuex Action to refresh it. This works well on the client side, but not if that process happens on the server side.
The Problem that's coming up on the server side is, that the user has to provide a refreshToken to get a refreshed accessToken from the API. This refreshToken is stored as a HttpOnly Cookie in the Client. When logging the Nuxt request details on the API side of things I noticed, that Nuxt is not sending that cookie.
My current workaround looks like this:
export const actions = {
async refreshToken(context){
...
let refreshToken
if (process?.server && this?.app?.context?.req?.headers?.cookie) {
const parsedCookies = cookie.parse(
this.app.context.req.headers.cookie
)
refreshToken = parsedCookies?.refreshToken
}
const response = await saveFetch(context, 'POST', '/auth/refresh-token', {
refreshToken,
})
...
}
...
}
If on server side, access the req object, get the cookies from it and send the refreshToken Cookie Content in the requests body.
This looks clearly bad to me and I would love to get some feedback on how to do this better. Did I maybe miss some key concepts that would help me not get into this problem in the first place?

how to use session in loopback using middlewre

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.

Redux: What is the correct place to save cookie after login request?

I have the following situation: The user enters his credentials and clicks a Login button. An API call is done in the action creator via redux-thunk. When the API call was successful, another action is dispatched containing the response from the server. After the (successful) login I want to store the users session id in a cookie (via react-cookie).
Action creator
export function initiateLoginRequest(username, password) {
return function(dispatch) {
dispatch(loginRequestStarting())
return fetch('http://path.to/api/v1/login',
{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: username,
password: password
})
})
.then(checkStatus)
.then(parseJSON)
.then(function(data) {
dispatch(loginRequestSuccess(data))
})
.catch(function(error) {
dispatch(loginRequestError(error))
})
}
}
export function loginRequestSuccess(user) {
return {
type: ActionTypes.LOGIN_REQUEST_SUCCESS,
user
}
}
Reducer
export default function user(state = initialState, action) {
switch (action.type) {
case ActionTypes.LOGIN_REQUEST_SUCCESS:
cookie.save('sessionId', action.user.sid, { path: '/' })
return merge({}, state, {
sessionId: action.user.sid,
id: action.user.id,
firstName: action.user.first_name,
lastName: action.user.last_name,
isAuthenticated: true
})
default:
return state
}
}
Right now the reducer responsible for LOGIN_REQUEST_SUCCESS saves the cookie. I know the reducer has to be a pure function.
Is saving a cookie in the reducer violating this principle? Would it be better to save the cookie inside the action creator?
Have a look at redux-persist.
You can persist/save your reducers (or parts of them) in LocalStorage.
Concept
Initiate login.
Receive cookie from server.
Dispatch login success.
Reducer stores cookie in memory.
Persist middleware stores reducer state in LocalStorage.
Example
Install
npm install --save-dev redux-persist
Example Usage
Create a component that wraps the persistence/rehydration logic.
AppProvider.js
import React, { Component, PropTypes } from 'react';
import { Provider } from 'react-redux';
import { persistStore } from 'redux-persist';
class AppProvider extends Component {
static propTypes = {
store: PropTypes.object.isRequired,
children: PropTypes.node
}
constructor(props) {
super(props);
this.state = { rehydrated: false };
}
componentWillMount() {
const opts = {
whitelist: ['user'] // <-- Your auth/user reducer storing the cookie
};
persistStore(this.props.store, opts, () => {
this.setState({ rehydrated: true });
});
}
render() {
if (!this.state.rehydrated) {
return null;
}
return (
<Provider store={this.props.store}>
{this.props.children}
</Provider>
);
}
}
AppProvider.propTypes = {
store: PropTypes.object.isRequired,
children: PropTypes.node
}
export default AppProvider;
Then, in your index.js or file in which you set up the store, wrap the rendered components in your new AppProvider.
index.js
...
import AppProvider from 'containers/AppProvider.jsx';
...
render((
<AppProvider store={store}>
...
</AppProvider>
), document.getElementById('App'));
This will serialize your user reducer state to LocalStorage on each update of the store/state. You can open your dev tools (Chrome) and look at Resources => Local Storage.
I'm not sure if this is the "right" way, but that's how my team is persisting the logged user in the Redux app we built:
We have a very default architecture, an API ready to receive requests in one side, and a React/Redux/Single Page app that consumes this API endpoints in the other side.
When the user credentials are valid, the API's endpoint responsible for the login respond to the app with the user object, including an access token. The access token is latter used in every request made by the app to validate the user against the API.
When the app receives this user information from the API two things happen: 1) an action is dispatched to the users reducer, something like ADD_USER, to include this user in the users store and 2) the user's access token is persisted in the localStorage.
After this, any component can connect to the users reducer and use the persisted access token to know who is the logged user, and of course if you have no access token in your localStorage it means the user is not logged in.
In the top of our components hierarchy, we have one component responsible to connect to the users reducer, get the current user based on the access token persisted in the localStorage, and pass this current user in the React's context. So we avoid every component that depends on the current user to have to connect to the users reducer and read from the localStorage, we assume that this components will always receive the current user from the app's context.
There are some challenges like token expiration that adds more complexity to the solution, but basically this is how we are doing it and it's working pretty well.
I'd probably have the server-side set the cookie, personally, and make it transparent to JavaScript. But if you really want to do it client-side, I'd do it in an action helper. Something like this:
// Using redux-thunk
function login(user, password) {
return dispatch => api.auth.login(user, password)
.then(result => setCookie())
.then(() => dispatch({type: 'USER_LOGGED_IN'}))
}
Or something like that.
Action helpers don't need to be pure, but reducers should be. So, if I'm doing side-effects, I put them into action helpers.

Sails REST API with simple AUTH

I'm pretty new to sails, but after read the doc and followed some examples at the Internet, I decided to give it a shot ;)
I have made an APP that depend on a REST webservice that I want to build in Sails Framework - but after a lots of research I haven't found the right solutions in sails yet.
I think I want to pass a (username, password) or a api_key in each webservice call made from the app?
All the examples that i found was only with a session login method - not with an API key in each call.
I used this tutorial - http://jethrokuan.github.io/2013/12/19/Using-Passport-With-Sails-JS.html
But only logins at post to login page - I want it to login in every call and still want to use the build in REST API blueprints.
The problem in my solution is that a call to like this - will not give me all the users as expected because of the default REST method - I want it to auth the user and give me the result ..
http://example.com:1337/user/?username=test&password=xxx
What is the "best practises" for building a APP with a REST webservice backend? - "with sails"
Some of my auth code:
// policies/authentication.js
if(req.param('username') && req.param('password')) {
UserAuth.auth(req, res, function(err, user) {
if (err) return res.forbidden('You are not permitted to perform this action.');
if(user) {
return next();
}
});
}else{
return res.forbidden('You are not permitted to perform this action.');
}
// services/UserAuth.js
module.exports = {
auth : function(req, res, cb) {
var bcrypt = require('bcrypt');
var passport = require("passport");
passport.authenticate('local', function(err, user, info){
if (err) return cb({ error: 'auth error!', status: 400 });
if(user) {
cb(null, user);
}
})(req, res);
}
}
// config/policies.js
module.exports.policies = {
'*': "authentication"
};
First off, it's bad practice to continuously expose usernames and passwords in the wild like this. At the very least, you should consider issuing access_tokens that expire after some time, and need to be re-issued via a login system.
Second, if you want to authenticate on every request (instead of using sessions), it's better to do so using a request header, rather than putting the credentials in the query string. This is especially true when using Sails blueprints; otherwise you'll have to do extra work to keep the blueprints from using your credentials as search criteria.
When using a header, per-request authorization becomes simple with Sails. Set up a policy in api/policies called (for example) auth.js:
module.exports = function (req, res, next) {
// Find an access header
var accessToken = req.header('my-auth-header');
// No header, no access
if (!accessToken) {return res.forbidden();}
// Find the user with that token
User.findOne({accessToken: accessToken})
.exec(function(err, user) {
// Handle error
if (err) {return next(err);}
// Handle bad access token
if (!user) {return res.forbidden();}
// Handle success
return next();
});
}
Then you can set any controller actions that need authentication using the config/policies.js file:
module.exports = {
SomeController: {
'*': 'auth'
},
...etc...
}

How to client side authentication with Emberjs

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.