I get an error when i try out my code 'Error: Unknown authentication strategy "spotify"'. I even tried googling this issue but can't didn't find an answer
Update: I updated my code to give answers to a person that is helping me
Code
const passport = require('passport')
const SpotifyStrategy = require('passport-spotify').Strategy
const userWebData = require('../model/userWebSchema')
passport.serializeUser((user, done) => {
const u = user
done(null, u)
})
passport.deserializeUser(async(spotifyID, done)=> {
try{
const data = await userWebData.findOne({ spotifyID: spotifyID})
const user = data
return user ? done( null, user) : done(null, null)
}catch(e){
console.log(e)
done(e, null)
}
})
passport.use(
new SpotifyStrategy({
clientID: 'Clients_ID_That_I_Wont_Show',
clientSecret: 'Clients_Secret_That_I_Wont_Show',
callbackURL: 'http://localhost:3001/',
scope: ["user-modify-playback-state", "user-read-private","user-library-read"]
}, async(accessToken, refreshToken, expires_in, profile, done)=>{
const userData = await userWebData.findOne({ spotifyID: profile.id})
if(userData){
console.log(`User ${profile.displayName} found`)
return done(err, userData);
}else{
let profiles = await userWebData.create(
{
spotifyID: profile.id,
spotifyName: profile.displayName,
spotifyFollowers: profile.followers,
}
)
profile.save()
console.log(`New User ${profile.displayName} Created`)
return done(err, userData);
}
}
)
)
You also have to import the passport-spotify package before authenticating with it. First, install the package (npm i passport-spotify) and then require it in your file:
const SpotifyStrategy = require('passport-spotify').Strategy;
Then, you have to call the passport.use() function before you can authenticate with passport:
passport.use(
new SpotifyStrategy(
{
clientID: client_id,
clientSecret: client_secret,
callbackURL: 'http://localhost:8888/auth/spotify/callback'
},
function(accessToken, refreshToken, expires_in, profile, done) {
User.findOrCreate({ spotifyId: profile.id }, function(err, user) {
return done(err, user);
});
}
)
);
Finally, you can use it as an Express middleware. Your modified code would look something like:
const express = require('express')
const app = express()
const passport = require('passport')
const SpotifyStrategy = require('passport-spotify').Strategy;
passport.use(
new SpotifyStrategy(
{
clientID: client_id,
clientSecret: client_secret,
callbackURL: 'http://localhost:8888/auth/spotify/callback'
},
function(accessToken, refreshToken, expires_in, profile, done) {
User.findOrCreate({ spotifyId: profile.id }, function(err, user) {
return done(err, user);
});
}
)
);
app.get('/', passport.authenticate('spotify'), (req, res)=>{
res.redirect('http://localhost:3001/user')
})
app.get('/user', (req, res) => {
if(req.user == undefined){res.status(401).redirect('http://localhost:3001/')}else{res.send(req.user)}
})
module.exports = app
Refer to http://www.passportjs.org/packages/passport-spotify/
Related
hello i new in backend and want to make a Authenticate facebook api with node js using express and i use passport but its not work and give me a page of html code as a response to sign in with facebook account this can handle when use web page the api may use with mobile application
my passport file that i use
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcryptjs');
const passport = require('passport')
const FacebookStrategy = require('passport-facebook').Strategy;
// Load User model
const User = require('../Schema/user');
// ---------------- Local Auth -------------- //
passport.use(
new LocalStrategy({ usernameField: 'email' },
(email, password, done) => {
// Search For Match user
User.findOne({ email: email }).then(user => {
if (!user) {
console.log("That email is not registered")
return done(null, false, { message: 'That email is not registered' });
}
// Compare the Two Password password
bcrypt.compare(password, user.password, (err, isMatch) => {
// if (err) throw err;
if (err) {
console.log(err)
return done(err);
}
if (isMatch) {
console.log("matching email");
return done(null, user);
} else {
console.log("Password incorrect");
return done(null, false, { message: 'Password incorrect' });
}
});
});
})
);
//------------------ Facebook Auth ---------------//
passport.use(new FacebookStrategy({
clientID: process.env.FACEBOOK_APP_ID,
clientSecret: process.env.FACEBOOK_APP_SECRET,
ccallbackURL: "/auth/facebook/callback",
profileFields: ['id', 'emails', 'name'],
},
async (accessToken, refreshToken, profile, done) => {
try {
const userData = {
firstName: profile._json.first_name.toLowerCase(),
lastName: profile._json.last_name.toLowerCase(),
email: profile._json.email,
isConfirmed: true,
};
// const user = await userService.registerWithThirdParty(userData);
done(null, user);
} catch (error) {
console.error(error.message);
done(null, false);
}
}
));
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
module.exports = passport;
my index.js file
router.get("/auth/facebook", passport.authenticate("facebook"));
router.get("/auth/facebook/callback",
function (req, res, next) {
passport.authenticate('facebook', function (err, user, info) {
if (err) { return next(err); }
if (!user) { return res.json({ message: info.message }) }
req.logIn(user, function (err) {
if (err) { return next(err); }
return res.json({ msg: "succes Login", user: user });
});
})(req, res, next);
}
);
when i use local signup or login it work but when i use facebook login dont work and give me a full html to sign in and i cant handled it in my api.
hint : i use passport-facebook
you can use this script to make authentication to facebook + passport js:
user.controller.js
import passport from "passport";
import dotenv from "dotenv";
import strategy from "passport-facebook";
import userModel from "../user/user.model";
const FacebookStrategy = strategy.Strategy;
dotenv.config();
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
passport.use(
new FacebookStrategy(
{
clientID: process.env.FACEBOOK_CLIENT_ID,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
callbackURL: process.env.FACEBOOK_CALLBACK_URL,
profileFields: ["email", "name"]
},
function(accessToken, refreshToken, profile, done) {
const { email, first_name, last_name } = profile._json;
const userData = {
email,
firstName: first_name,
lastName: last_name
};
new userModel(userData).save();
done(null, profile);
}
)
);
user.router.js
import express from "express";
import passport from "passport";
import userController from "./user.controller";
const userRouter = express.Router();
userRouter.get("/auth/facebook", passport.authenticate("facebook"));
userRouter.get(
"/auth/facebook/callback",
passport.authenticate("facebook", {
successRedirect: "/", // to add check you can use this value successRedirect also the next value failureRedirect
failureRedirect: "/fail"
})
);
userRouter.get("/fail", (req, res) => {
res.send("Failed attempt");
});
userRouter.get("/", (req, res) => {
res.send("Success");
});
export default userRouter;
index.js
import express from "express";
import { json } from "body-parser";
import passport from "passport";
import { connect } from "./utils/db";
import userRouter from "./user/user.routes";
const app = express();
const port = 3000;
app.use(passport.initialize());
app.use(json());
app.use("/", userRouter);
app.listen(port, async () => {
await connect();
console.log(`Server listening on ${port}`);
});
I have configured passportJS with node express app but when I make login/register request then in that case req.user is undefined any idea what is wrong am I missing something in configuring passport js? I have used express-session and mongoDB store for storing sessions
passport-config.js:
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
const User = require("./Models/userSchema");
passport.use(
new LocalStrategy(
{
usernameField: "email",
passwordField: "password",
},
async (email, password, done) => {
try {
const user = await User.findOne({ email });
// Username/email does NOT exist
console.log("user in config", user);
if (!user) {
return done(null, false, {
message: "Username/email not registered",
});
}
// Email exist and now we need to verify the password
const isMatch = await user.isValidPassword(password);
return isMatch
? done(null, user)
: done(null, false, { message: "Incorrect password bro" });
} catch (error) {
done(error);
}
}
)
);
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(async function (id, done) {
const user = await User.findById(id);
done(null, user);
});
server.js file: https://pastebin.com/NfpvXSFf (see line 39)
I would try:
async (req, res) => {
{email, password, done} = req.body;
(you need a body-parser for that)
I am attempting to use Passport.js to authorize Google OAuth2 on Node.js. I have tried all week to make it work and have no idea why it isn't, so am now resorting to stack for some potential help. I have tried all solutions to similar problems available on forums online.
Each time it sends the request it returns TokenError: Bad Request, however, it is able to console.log the required data, so this to me demonstrates that the token was in fact successful. I cannot explain why this is occurring.
I have tried being more specific in callback request e.g http://localhost:3000/auth/google/redirect.
I have tried every other type of Oauth type google has Node server, web application, html ect.
I have tried different ports.
AUTH ROUTES
const router = require('express').Router();
const passport = require('passport');
// auth login
router.get('/login', (req, res) => {
res.render('login', { user: req.user });
});
// auth logout
router.get('/logout', (req, res) => {
// handle with passport
res.send('logging out');
});
// auth with google+
router.get('/google', passport.authenticate('google', {
scope: ['profile']
}));
// callback route for google to redirect to
// hand control to passport to use code to grab profile info
router.get('/google/redirect', passport.authenticate('google'),
(req,
res) => {
res.send('you reached the redirect URI');
});
module.exports = router;
PASSPORT_SETUP
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const keys = require('./keys');
passport.use(
new GoogleStrategy({
// options for google strategy
clientID: keys.google.clientID,
clientSecret: keys.google.clientSecret,
callbackURL: '/auth/google/redirect'
}, (accessToken, refreshToken, profile, done) => {
// passport callback function
console.log('passport callback function fired:');
console.log(profile);
})
);
When submitted the process progresses through SignIn page, delivers desired result the console.log and then just sits for about 1 minute awaiting localhost.
As you can see the very thing it is trying to retrieve is already in the console.
It then progresses to throw and Error:
Sorry for the late reply, dug up some old code this is the point where it was marked as 'All auth methods functioning'. As stated by Aritra Chakraborty in the comments, "done" method was not being called. See the following implementation with Nedb.
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const Datastore = require('nedb');
const database = new Datastore('database.db');
database.loadDatabase();
passport.serializeUser((user, done) => {
done(null, user.googleId || user.id);
});
passport.deserializeUser((googleId, done) => {
database.findOne({ googleId : googleId }, (err, user) => {
done(null, user);
});
});
var strategy = new GoogleStrategy({
// options for google strategy
clientID: keys.google.clientID,
clientSecret: keys.google.clientSecret,
callbackURL: '/auth/google/redirect'
}, (accessToken, refreshToken, object0, profile, done) => {
// check if user already exists in our own db
database.findOne({ googleId: profile.id }, (err, currentUser) => {
if (currentUser !== null) {
done(null, currentUser);
} else {
var d = new Date();
var n = d.getTime();
var duoID = uuidv1();
var User = {
duoVocalID: duoID,
googleId: profile.id,
username: profile.displayName,
thumbnail: profile._json.image.url,
oscope: object0.scope,
oaccess_token: object0.access_token,
otoken_type: object0.token_type,
oid_token: object0.id_token,
oexpires_in: object0.expires_in,
oemails: profile.emails,
olanguage: profile._json.language,
oname: profile.name,
TimeOfLastLogon: n,
RefreshToken: refreshToken
};
database.insert(User, (err, newUser) => { });
var newUser = User;
done(null, newUser);
}
});
});
passport.use(strategy);
// auth with google+
app.get('/auth/google', passport.authenticate('google', {
scope: ['profile', 'email', 'https://www.googleapis.com/auth/spreadsheets'],
accessType: 'offline',
approvalPrompt: 'force'
}));
// callback route for google to redirect to
// hand control to passport to use code to grab profile info
app.get('/auth/google/redirect', passport.authenticate('google'), async (req, res) => {
var userString = JSON.stringify(req.user)
jwt.sign({userString}, 'secretKey', { expiresIn: '365d' }, (err, token) => {
res.send("<script>localStorage.setItem('token', '"+token+"'); window.close(); window.opener.document.getElementById('modal-toggle').checked = false;</script>");
});
});
I have a problem where I can't redirect user to angular route, like here's the example:
I am on login page, click google login, redirected to google, successfully logged in, and after that i want to go in my app, like news feed.
What I did by far is with passport is within express app. Here are the routes and passport strategy for google.
router.get('/google', passport.authenticate('google', {
scope: ['profile', 'email']
}))
router.get('/google/callback', passport.authenticate('google', {
successRedirect: '/profile',
failureRedirect: '/'
}))
And this is the google strategy where I store user.
passport.use(new GoogleStrategy({
clientID: Config.google.GOOGLE_CLIENT_ID,
clientSecret: Config.google.GOOGLE_CLIENT_SECRET,
callbackURL: Config.google.CALLBACK_URL,
passReqToCallback : true
},
function(req, token, refreshToken, profile, done) {
process.nextTick(function() {
if (!req.user) {
User.findOne({ 'google.id' : profile.id }, function(err, user) {
if (err) { return done(err) }
if (user) {
if (!user.google.token) {
user.google.token = token
user.google.name = profile.displayName
user.google.email = profile.emails[0].value;
user.username = profile.displayName.replace(/\s+/g, '-').toLowerCase();
user.save(function(err) {
if (err) { throw err }
return done(null, user)
})
}
return done(null, user)
} else {
var newUser = new User()
newUser.google.id = profile.id
newUser.google.token = token
newUser.google.name = profile.displayName
newUser.google.email = profile.emails[0].value;
newUser.username = profile.displayName.replace(/\s+/g, '-').toLowerCase();
newUser.save(function(err) {
if (err) { throw err }
return done(null, newUser)
})
}
})
} else {
var user = req.user
user.google.id = profile.id
user.google.token = token
user.google.name = profile.displayName
user.google.email = profile.emails[0].value;
user.username = profile.displayName.replace(/\s+/g, '-').toLowerCase();
user.save(function(err) {
if (err) { throw err }
return done(null, user)
})
}
})
}))
So how can I make this to redirect on angular route which is like localhost:4200/app/feed for example, which is the flow on normal email login.
can you configure it here and check
router.get('/google/callback', passport.authenticate('google', {
successRedirect: '/profile',
failureRedirect: '/'
}))
to
router.get('/google/callback', passport.authenticate('google', {
successRedirect: '/app/feed',
failureRedirect: '/'
}))
i am trying to learn node.js and having a bit of a headache doing the express login storing cookies with google oauth. I am using mongodb, user gets saved without a problem.
I can log in just fine, but when i set the cookies baaaam. But there is no error on console.
If i try to set cookies using cookies-session and express, the app hangs and i can't access any route '/' even the '/logout'. I only able to access them again if i clear the cookies on browser. I am stuck at this point.
this is my app.js
app.use(
cookieSession({
maxAge: 30 * 24 * 60 * 60 * 1000,
keys: [keys.cookieSession]
})
);
app.use(passport.initialize());
app.use(passport.session());
my routes
app.get('/auth/google',
passport.authenticate('google', {
scope: ['profile', 'email']
})
);
app.get('/auth/google/callback', passport.authenticate('google'));
app.get('/api/logout', (req, res) => {
req.logout();
res.send(req.user);
});
and my passport.js
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id).then(user => {
done(err, user);
});
});
passport.use( new GoogleStrategy({
clientID: keys.googleClientID,
clientSecret: keys.googleClientSecret,
callbackURL: '/auth/google/callback'
},
(accessToken, refreshToken, profile, done) => {
User.findOne({ googleId: profile.id }).then((existingUser) => {
if (existingUser) {
// don't create a new user
done(null, existingUser);
} else {
// create a new user
new User ({ googleId: profile.id }).save()
.then(user => (null, user));
}
})
}
));
So i was able to get this working, but I want to know what was did wrong.
I changed this and it worked, anyone has a clue?
passport.deserializeUser((id, done) => {
User.findById(id).then(user => {
done(err, user);
});
});
to
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});