Hi I'm using Auth0 with Nodejs and angularjs
here is what i want to achieve
1. I want to user to signup using auth0's lock
2. as soon as user logs in a callback should be called at my nodejs server
3. after that i will get the user information and user's JWT
4. then i will redirect user to dashboard page and store the JWT in browser
What's the problem with Auth0's example
1. they provide example either for angular or nodejs standalone not the combined
2. there is combined(client server) example but that's using jade with nodejs
my code snipped
Angular snipped
var options = { auth: {
redirectUrl: 'http://localhost:3000/callback'
, responseType: 'code'
, params: {
scope: 'openid name email picture'
}
}
}
lockProvider.init({
clientID: 'cUlBNhhaIblahBlahRp6Km',
domain: 'rishabh.auth0.com',
option:options
});
node snipped
router.get('/callback',
passport.authenticate('auth0', { failureRedirect: '/url-if-something-fails' }),
function(req, res) {
console.log(req.user);
res.json({id_token:req.user});
});
Note: I've added this callbacks in auth0
http://localhost:3000/callback
but dont know why I'm facing this error for callback error when I've mentioned my redirect URL in angular side
can anyone tell me what is the problem with my code why auth0 not redirecting me to this url http://localhost:3000/callback
and the interesting thing is when i use simple lock.js instead of angular like this
<script>
var options = { auth: {
redirectUrl: 'http://localhost:3000/callback'
, responseType: 'code'
, params: {
scope: 'openid name email picture'
}
}
}
var lock = new Auth0Lock('clientID', 'rishabh.auth0.com',options);
lock.show();
</script>
then in this case my nodejs /callback route is called properly, so what I'm doing wrong with angular ?
please help
Update
this is my project structure
full code
https://github.com/LabN36/error
Config.js
var Auth0Strategy = require('passport-auth0');
var passport = require('passport');
var strategy = new Auth0Strategy({
domain: process.env.AUTH0_DOMAIN || 'rishabh.auth0.com',
clientID: process.env.AUTH0_CLIENT_ID || 'cUheWwRxm7OLdHBRzlBNvfvfvfvfvhhaI1lxRp6Km',
clientSecret: process.env.AUTH0_CLIENT_SECRET || 'e37eIZpjgBnDMBtrYMwvffvfvfvfaU4jSqt8qylZMT9Oj1EiffLGViinWQ5AiuWi1-WBwA8v3',
callbackURL: process.env.AUTH0_CALLBACK_URL || 'http://localhost:3000/callback'
}, function(accessToken, refreshToken, extraParams, profile, done) {
// accessToken is the token to call Auth0 API (not needed in the most cases)
// extraParams.id_token has the JSON Web Token
// profile has all the information from the user
console.log(extraParams.id_token);
//save user detail with token here and return token only profile
return done(null, extraParams.id_token);
});
passport.use(strategy);
// you can use this section to keep a smaller payload
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
module.exports = passport;
AngularApp.js
angular.module('workApp',['auth0.lock'])
.config(function($locationProvider,lockProvider){
var options = { auth: {
// redirect:true,
responseType: 'code',
redirectUrl: 'http://localhost:3000/callback',
params: {
scope: 'openid name email picture'
}
}
}
lockProvider.init({clientID: 'cUheWwRxm7OLdHBRzlBNhhaI1lxRp6Km',domain: 'rishabh.auth0.com',
option:options
});
$locationProvider.html5Mode(true);
})
.controller('homeCtrl',function($scope,$http,$location,$window,lock){
$scope.login = function() {
// window.alert("magic")
console.log("Messed Up really")
var vm = this;
vm.lock = lock;
lock.show();
}
}).run(function(lock){
lock.interceptHash();
lock.on('authenticated', function(authResult) {
localStorage.setItem('id_token', authResult.idToken);
lock.getProfile(authResult.idToken, function(error, profile) {
if (error) {
console.log(error);
}
localStorage.setItem('profile', JSON.stringify(profile));
});
});
})
According to the screenshot the error happens because the authentication request is made with a redirect_uri of:
http://localhost:3000/
and the allowed callback URL's are:
http://localhost:3000/callback
http://35.162.118.253:3000/callback
Also based on the code you shared you're indeed setting the redirectUrl to be http://localhost:3000/callback so there may be something on the rest of the code that either causes that value to be overridden or not used at all.
If the redirectUrl is not set, Lock will use the current page so the likely culprit is that the options you set are not being used. If you still don't find the cause for this, update the question with the code associated with how Lock is shown.
Damn, the actual root cause was already shown in the code you initially provided, but only looking now at the full code made it possible for me to catch it...
You're calling lockProvider.init() with:
{ clientID: [?], domain: [?], option: options }
when it should be called with:
{ clientID: [?], domain: [?], options: options } // options instead of option
Related
I created the okta sigin login page using angularjs and I got the response as success for okta api.how to redirect the page after login. I have attached the screenshot below:
please find the solution....
Not able to redirect the page after response success please check the code using angularjs with okta authentication login :
var oktaSignIn = new OktaSignIn({
authParams: {
responseType: 'id_token',
responseMode: 'okta_post_message',
scopes: ['openid', 'groups'],
// data : JSON.stringify(data1)
},
clientId: OKTA_CLIENT_ID,
baseUrl: OKTA_ORG_URL,
//redirectUri: "http://localhost:8080",
});
oktaSignIn.renderEl(
{ el: '#okta-login-container' },
function (res) {
if (res.status == 'SUCCESS') {
alert("User successfully authenticated");
console.log(res);*/
$location.path("https://www.google.com/");
}
);
On my frontend, I can see the email through:
console.log(auth.profile.email)
Then I call this service to retrieve some information from the backend, it's protected so you need to be logged in to get anything back:
var metadata_req = {
method: "GET",
url: "http://localhost:80/protected/all/metadata"
}
On the backend, I'm using node.js and this to verify that the user is logged in before doing a request:
var jwtCheck = express-jwt({
secret: new Buffer(config.secret, 'base64'),
audience: config.client_id
});
But if I print out req.user, I only see iss, sub, aud, exp and iat. I would like to see the email as well.
You can get profile information in req.user by including the email permission when your user initially logs in.
For example, using lock in angular would look like this:
auth.signin({
authParams: {
scope: 'openid email'
}
}, function(profile, token) {
// stuff
}, function(err) {
// error handling
});
Change your API definition from "all/metadata" to "all/metadata/:emailId"
Call your API
var metadata_req = {
method: "GET",
url: "http://localhost:80/protected/all/metadata/{your_email_id}"
}
In NodeJS retrieve you email_id from req.params.emailId
I have implemented client side routing using 'Angular UI router'. I am using passport facebook strategy at the server side to handle facebook based authenticatoin.
I have my angular routes as follows:
angular.module('homepage').
config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
// INDEX STATES ========================================
.state('index', {
url: '/',
templateUrl: '../../html/partials/partial-index.html'
})
// HOME PAGE AND MULTIPLE NAMED VIEWS =================================
.state('home', {
url: '/home',
templateUrl: '../../html/partials/partial-home.html'
});
});
Now i initiate the authentication on click to following link:
<a class="clickable" href="/auth/facebook">Log In</a>
Following are my server side routes:
// route for facebook authentication and login
app.get('/auth/facebook',
passport.authenticate('facebook', {
scope : 'email'
}));
// handle the callback after facebook has authenticated the user
app.get('/auth/facebook/callback',
passport.authenticate('facebook', {
successRedirect : '/success',
failureRedirect : '/login'
}));
app.get('/success', isLoggedIn, function(req, res) {
// client side redirection without passing user info
res.redirect('/#/home');
});
On authentication success, my page reloads and loads 'localhost:8888/#/home' and loads the 'home' route state. But the issue is that i have not recieved any user info at the client side after redirection happened.
Ideally i would like to do something as follows:
app.get('/success', isLoggedIn, function(req, res) {
// what i would like to do ideally
res.json({
path: '/#/home',
user : req.user // get the user out of session and pass to template
});
});
But I dont know how to pass this info to angularjs current page context from nodejs routes. How can i implement this.
What is the good approach to authenticate via facebook strategy and then do angular route redirection while passing user info to angular.
You should write a custom response handler for passport when you use a strategy. Like this:
passport.use(new FacebookStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET,
callbackURL: "http://localhost:3000/auth/facebook/callback"
},
function(accessToken, refreshToken, profile, cb) {
User.findOrCreate({ facebookId: profile.id }, function (err, user) {
return cb(err, user);
});
}
));
Are you wrote that?
Don't forget about user serialization:
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
Hi I want to support both formbased authentication and http basic authentication in my app. Everything works as expected except when I use form based auth via angularjs with wrong credentials.
Instead of having my angular code handle the 401, the browser shows the BASIC auth dialog, caused by the WWW-Authenticate header.
How can I prevent that header from being added when the local strategy is used?
Or how can I support both mechanisms in a different way?
I use the following route in my express based app.
api.post('/authenticate', passport.authenticate(['local', 'basic'], { session: false }), function (req, res) {
This enables both authentication methods on that url. I repeat, when I use wrong credentials using formbased it shows me the basic auth dialog (I don't want that).
Following is how I registered the strategies.
passport.use(new BasicStrategy({ realm: 'Authentication failed. Wrong username or password.'}, verifyLocalUser));
passport.use(new LocalStrategy(verifyLocalUser));
This is how my verifyUser method looks like...
var verifyLocalUser = function (username, password, next) {
User.findOne({
username: username
}).select('fullname admin username password').exec(function (err, user) {
if (err) {
return next(err);
}
if (user && user.comparePasswords(password)) {
return next(null, user);
} else {
next(null, false, { message: 'Authentication failed. Wrong username or password.' });
}
});
}
Does anyone know how to support multiple authentication methods using passport.js?
For completeness, this is the angular code which authenticates me...
authFactory.signIn = function (username, password) {
return $http.post('/api/authenticate', {
username: username,
password: password
}).then(function (res) {
AuthToken.setToken(res.data.token);
return res.data;
}, function (res) {
console.warn(res);
});
};
instead of this:
next(null, false, { message: 'Authentication failed. Wrong username or password.' });
You can use this:
cb(new YourCustomError())
And "YourCustomError" can have a message, for me mine "YourCustomError" looks like:
class HttpError extends Error {
constructor (msg = 'Invalid Request', status = 400) {
super(msg)
this.status = status
}
}
class Forbidden extends HttpError {
constructor (msg = 'Forbidden') {
super(msg, 403)
}
}
Or probably new Error(<message>) will work properly for you, too
Currently I been using a chrome app called Postman to test my services from nodejs/express/passportjs.
Currently I'm having trouble wrapping my head around how I should grab the user info and authenticate it with backbone.
I would try to authenticate the user like so:
$.post("http://localhost:3000/login", { username: "joe", password: "pass" })
.done(function(data) {
console.log(data)
//try to pull a service that's protected by passport
})
.fail(function(data) {
console.log(data)
})
Which is not working at all when it's successful. Its giving the 500 error I set for when someone isn't logged in.
Any particular direction I should be going in to manage authentication with passportjs in backbone?
The 500 error means some part of the code in the server is not working properly.
You can send the logged in user from express using passport. You can follow the following example.
var app = express();
var login = require('./routes/login');
app.post('/login',
passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login',
failureFlash: true }),
login.login);
where your login.js file may look like this
exports.login = function (req, res) {
res.json(req.user);
}
the authenticate process of passport populates user variable in request (req) with the logged in user.
Please note, you have to use cookie parser and session of express to make the passport session working. e.g.,
app.use(express.cookieParser());
app.use(express.session({ secret: 'keyboard cat' }));
your local authentication may look like the following (say you have a function that finds user by username (findByUsername)).
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
},
function(username, password, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
// Find the user by username. If there is no user with the given
// username, or the password is not correct, set the user to `false` to
// indicate failure and set a flash message. Otherwise, return the
// authenticated `user`.
findByUsername(username, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
if (user.password != password) { return done(null, false, { message: 'Invalid password' }); }
return done(null, user);
})
});
}
));