My application is in nodejs, and im integrating for Paypal authentication using passport-paypal
Middleware code
const PPStrategy = require('passport-paypal').Strategy;
passport.use(
new PayPalStrategy(
{
clientID: 'My Paypal clientID',
clientSecret: 'My PayPal secret Id',
returnURL: 'localhost:4000/paypal/callback',
scope: 'openid'
},
function(identifier, done, next) {
return next(null, identifier);
}
)
);
ppRouter.get('/paypal', passport.authenticate('paypal'));
ppRouter.get(
'/paypal/callback',
passport.authenticate('paypal', { failureRedirect: '/Home' }),
function(req, res) {
//My logic on successful authentication
res.redirect('/Home/Payments');
}
);
The above implementation gives me the error
{"message":"Failed to discover OP endpoint URL"}
I have tried to pass callbackUrl instead of returnUrl URL in the strategy but i get the same issue.
Related
I have created a MERN application with a separate backend and frontend. I have added support for Google Oauth2 login using passport-google-oauth20 npm package.
So I have exposed an end point in the backend as follows:
class AccountAPIs {
constructor() { }
redirectToSuccess(req, res) {
const accountServiceInst = AccountService.getInst();
let account = req.session.passport.user;
let filePath = path.join(__dirname + '../../../public/views/loginSuccess.html');
let jwt = accountServiceInst.generateJWT(account);
// how do I send this jwt to ui application
res.sendFile(filePath);
}
loadMappings() {
return {
'/api/auth': {
'/google': {
get: {
callbacks: [
passport.authenticate('google', { scope: ['profile', 'email'] })
]
},
'/callback': {
get: {
callbacks: [
passport.authenticate('google', { failureRedirect: '/api/auth/google/failed' }),
this.redirectToSuccess
]
}
},
'/success': {
get: {
callbacks: [this.successfulLogin]
}
}
}
}
};
}
}
Here is the passport setup for reference:
let verifyCallback = (accessToken, refreshToken, profile, done) => {
const accountServiceInst = AccountService.getInst();
return accountServiceInst.findOrCreate(profile)
.then(account => {
return done(null, account);
})
.catch(err => {
return done(err);
});
};
let googleStrategyInst = new GoogleStrategy({
clientID: serverConfig.auth.google.clientId,
clientSecret: serverConfig.auth.google.clientSecret,
callbackURL: 'http://localhost/api/auth/google/callback'
}, verifyCallback);
passport.use(googleStrategyInst);
In the UI application, on button click I am opening a new window which opens the '/api/auth/google' backend API. After authenticating with a google account, the window redirects to the '/api/auth/google/callback' backend API where I am able to generate a JWT. I am unsure about how to transfer this JWT to the frontend application since this is being opened in a separate window.
I know that res.cookie('jwt', jwt) is one way to do it. Please suggest the best practices here..
There are two ways to pass the token to the client :
1- you put the token into a cookie as you have mentioned
2-you pass the token in the redirect URL to the client as a parameter "CLIENT_URL/login/token", that you can extract the token in your front-end client
I have an iOS app and nodeJS backend. Currently I have implemented passport-facebook strategy. From the app I get the facebook token, and I send it to backend where I authorise the user.
// config
var FacebookTokenStrategy = require('passport-facebook-token');
const passport = require('passport')
const { facebook_client_id, facebook_client_secret } = require('../config')
passport.use(new FacebookTokenStrategy({
clientID: facebook_client_id,
clientSecret: facebook_client_secret,
}, function (accessToken, refreshToken, profile, done) {
done(null, profile)
}
));
And the middleware
const passport = require('passport')
require('../config/passport-facebook')
require('../config/passport-apple')
require('../config/passport')
const { INVALID_TOKEN, UNAUTHORIZED } = require('../config/constants')
module.exports = (req, res, next) => {
passport.authenticate(['apple','facebook-token', 'jwt'], function (err, user, info) {
if (err) {
if (err.oauthError) {
res
.status(400)
.json({ message: INVALID_TOKEN })
}
} else if (!user) {
res
.status(401)
.json({ message: UNAUTHORIZED })
} else {
req.user = user
next()
}
})(req, res, next);
}
Now I need to implement apple login. I tried using this library passport-apple
But I can not make it work. I am receiving the token from the app, send it to the back, but I only get
GET - /api/v1/shirts/?sorted%5BcreatedAt%5D=-1&filtered%5Bstate%5D=&pageNum=1&pageSize=10 - 302 - Found - 0b sent - 15 ms
I don't know if this is the correct approach. Should I get the user info from the app, send it to the backend and assign a JWT token to the created user? Or how can I do the same as I did with facebook?
After several try I find the solution thanks to this documentation https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens
You need to send that in your body POST:
{
"grant_type": "authorization_code",
"code": "YOUR_CODE",
}
code:
"The authorization code received in an authorization response sent to your app. The code is single-use only and valid for five minutes. This parameter is required for authorization code validation requests." Apple Documentation
I have registered an OAuth App via my Github account. I am basically trying to authorize my node requests(by sending access_token as part of request cookies) so I can access few APIs on another server. Hence I am using the github-passport2 package. I have setup the github strategy etc. & it seems to be all according to the doc. The flow works well too.
My Issue
After logging into Github(authorized) & getting redirected back to my /auth/github/callback, I ideally should be authorized and should have an access_token in the req. But I don't have it! Because of this I am not able to authorize my future requests with an access_token.
Important to note is that, this access_token is automatically attached when the request is initiated from a browser/client(using withCredentials: true parameter). The same access_token via node doesn't seem to be retrievable.
passport.use(new GitHubStrategy({
clientID: GITHUB_CLIENT_ID,
clientSecret: GITHUB_CLIENT_SECRET,
callbackURL: "http://localhost:8080/auth/github/callback",
},
function(accessToken, refreshToken, profile, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
return done(null, profile);
});
}
));
app.get('/auth/github', passport.authenticate('github', { scope: [ 'user:email' ] }), function(req, res){
// The request will be redirected to GitHub for authentication, so this
// function will not be called.
});
app.get('/auth/github/callback', passport.authenticate('github', { failureRedirect: '/login' }), function(req, res) {
console.log(req); // <- This ideally should have the access_token? but doesn't
});
I have struggling for days on this. Any help is much appreciated.
Using: passport-google-oauth2.
I want to use JWT with Google login - for that I need to disable session and somehow pass the user model back to client.
All the examples are using google callback that magically redirect to '/'.
How do I:
1. Disable session while using passport-google-oauth2.
2. res.send() user to client after google authentication.
Feel free to suggest alternatives if I'm not on the right direction.
Manage to overcome this with some insights:
1. disable session in express - just remove the middleware of the session
// app.use(session({secret: config.secret}))
2. when using Google authentication what actually happens is that there is a redirection to google login page and if login is successful it redirect you back with the url have you provided.
This actually mean that once google call your callback you cannot do res.send(token, user) - its simply does not work (anyone can elaborate why?). So you are force to do a redirect to the client by doing res.redirect("/").
But the whole purpose is to pass the token so you can also do res.redirect("/?token=" + token).
app.get( '/auth/google/callback',
passport.authenticate('google', {
//successRedirect: '/',
failureRedirect: '/'
, session: false
}),
function(req, res) {
var token = AuthService.encode(req.user);
res.redirect("/home?token=" + token);
});
But how the client will get the user entity?
So you can also pass the user in the same way but it didn't felt right for me (passing the whole user entity in the parameter list...).
So what I did is make the client use the token and retrieve the user.
function handleNewToken(token) {
if (!token)
return;
localStorageService.set('token', token);
// Fetch activeUser
$http.get("/api/authenticate/" + token)
.then(function (result) {
setActiveUser(result.data);
});
}
Which mean another http request - This make me think that maybe I didnt get right the token concept.
Feel free to enlighten me.
Initialize passport in index.js:
app.use(passport.initialize());
In your passport.js file:
passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL:
'http://localhost:3000/auth/google/redirect',
},
async (accessToken, refreshToken, profile,
callback) => {
// Extract email from profile
const email = profile.emails![0].value;
if (!email) {
throw new BadRequestError('Login failed');
}
// Check if user already exist in database
const existingUser = await User.findOne({ email
});
if (existingUser) {
// Generate JWT
const jwt = jwt.sign(
{ id: existingUser.id },
process.env.JWT_KEY,
{ expiresIn: '10m' }
);
// Update existing user
existingUser.token = jwt
await existingUser.save();
return callback(null, existingUser);
} else {
// Build a new User
const user = User.build({
email,
googleId: profile.id,
token?: undefined
});
// Generate JWT for new user
const jwt = jwt.sign(
{ id: user.id },
process.env.JWT_KEY,
{ expiresIn: '10m' }
);
// Update new user
user.token = jwt;
await auth.save();
return callback(null, auth);
}
}));
Receive this JWT in route via req.user
app.get('/google/redirect', passport.authenticate('google',
{failureRedirect: '/api/relogin', session: false}), (req, res) => {
// Fetch JWT from req.user
const jwt = req.user.token;
req.session = {jwt}
// Successful authentication, redirect home
res.status(200).redirect('/home');
}
I'm currently looking at implementing a google api, using the nodejs client:
https://github.com/google/google-api-nodejs-client/
I'm trying to use passport in order to authenticate, which seems to be working#
passport.use(new GoogleStrategy({
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/google/callback"
},
function(accessToken, refreshToken, profile, done) {
process.nextTick(function () {
var user = {
id: profile.id,
email: profile.email,
firstName: profile.given_name,
lastName: profile.family_name,
accessToken: accessToken
};
return done(null, user);
});
}
));
In my google auth callback:
app.get('/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/login' }),
function(req, res) {
//do something here with the google api
});
I can get hold of req.user, and this has the accessToken
However, the docs for the Google api nodejs client aren't clear on how to use an accessToken.
The example included shows the OAauth2Client retrieving a token, but I guess that part has already been covered using Passport?
I'm not familiar with google-api-nodejs-client, but this is in their documentation:
oauth2Client.credentials = {
access_token: 'ACCESS TOKEN HERE',
refresh_token: 'REFRESH TOKEN HERE'
};
client
.plus.people.get({ userId: 'me' })
.withAuthClient(oauth2Client)
.execute(callback);
I assume you can just set the credentials to those provided by Passport, and things will work fine.
Honestly, though, I find these API wrappers really contrived, and recommend just using request. That way you can access any API service from any provider using a familiar module.