Hey I am trying to work out where the bearer token is in a mean.io project.
I am using the default project which has Oauth enabled by default (have put the api keys in) and I can successfully log in.
How is passport storing the bearer token so I can authenticate my API calls? What is the best way to access it?
The token that is returned by the OAuth authentication is discarded by MEAN. See https://github.com/linnovate/mean/blob/v0.4.4/packages/users/passport.js:
passport.use(new FacebookStrategy({
clientID: config.facebook.clientID,
clientSecret: config.facebook.clientSecret,
callbackURL: config.facebook.callbackURL
},
function(accessToken, refreshToken, profile, done) {
// accessToken and refreshToken not used, not stored.
});
}
));
You could provide your own strategies to override this behavior, or try to raise the issue with MEAN. I see you already made a ticket. I'm afraid this may be a security consideration on their part, as there is no risk of losing the tokens if they are not stored.
Related
I am using google oauth passport strategy in my nodejs app and I don't know the right way to store and renew my idToken, so I can use it for authentication purposes when making api calls to an external api. Presently, I'm writing the token to a textfile and reading it from there. I feel this is a bad idea and just need suggestions on how to do it in a more elegant way.
module.exports = function (passport) {
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: url },
async (accessToken, refreshToken, params, profile, done) => {
const idToken = params.id_token
fs.writeFile('token.txt', idToken, err => {
if (err) {
console.error(err)
return
}
//file written successfully
console.log("file written successfully")
})
}
As another poster indicated, if you are using the token purely for login, you may not need to store and renew the ID token at all.
However, if you are using the token to access Google APIs, and you need access even without the user present, the most common approach is:
Store the access token and refresh token encrypted in a database, both associated with the user
When using the access token, check for an error response from Google that indicates that the token has expired, use the refresh token to get a new access token, and save that new access token in your database (again, encrypted)
In Google's case, be sure to pass the access_type=offline parameter to retrieve an refresh token. Also, if this is a user you have previously authorized, you'll need to pass prompt=consent, as otherwise Google will not issue a refresh token.
An alternative to implementing all of the above is to use a managed OAuth service like Xkit, where I work. It handles storing, encrypting, and refreshing tokens, and all of the provider-specific nuances. Again, only useful in cases where you're using the tokens to access APIs (and not for login), but another option to consider.
I'm trying to implement Facebook login with Passport for my app hosted with an Herokuapp domain but I've been getting the above error message even after setting the values for app domain, website and OAUTH redirect URL.
Nothing I've seen here from previous answers seem to be working. Screenshots provided below
I was having this same issue, what finally worked for me was to make sure that the callbackURL exactly matched what was in Facebook's 'Valid OAuth Redirect URIs'.
For example, if you have https://example.com/auth/facebook/callback as a callback URI, then you need to have it listed exactly the same within your code -
passport.use(new FacebookStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET,
callbackURL: 'https://example.com/auth/facebook/callback',
}, async (accessToken, refreshToken, profile, done) => {
...
}),
);
I had been using /auth/facebook/callback for my callbackURL, but it had to be the exact value that was given to Facebook in your apps settings.
Additionally, you may need to include the www version of your site in both your App Domains and your Valid OAuth Redirect URIs, as Facebook will throw an error if you try to go to https://www.example.com when you have only included https://example.com.
I have just fixed my issue. I receive the same error message when trying connect Facebook login with passport lib. My solution is to use full callback url instead. The code is below:
const FacebookStrategy = require('passport-facebook').Strategy
passport.use(
new FacebookStrategy({
clientID: process.env.FACEBOOK_ID,
clientSecret: process.env.FACEBOOK_SECRET,
callbackURL: 'https://your_domain.com/facebook/callback'
},
function(accessToken, refreshToken, profile, done) {
done(null, {profile: profile})
}
))
Hoping this is useful for you
Imagine I'm implementing an API service at api.example.com that needs to protect its endpoints using OAuth2 with sufficient granularity to accommodate different user types.
users who authenticate against Facebook can only access https://api.example.com/facebook
users who authenticate against Twitter can only access https://api.example.com/twitter
users who authenticate locally against the Authorization service can access both facebook and twitter endpoints
This means we have the following roles:
Authentication provider (Authorization server, Facebook, Twitter)
An Authorization provider (My OAuth2 server) (auth.example.com)
A Resource provider (My API server) (api.example.com)
An ExpressJS webapp or SPA (www.example.com), or native app
Questions:
Q1 How should the application flow be implemented?
My thoughts are ...
A webapp must store the accessToken to api.example.com in a session, and send the sessionid to the web browser. If there is no accessToken, it must redirect the browser to auth.example.com/login/selectprovider/, providing the client_id="www.example.com" and client_secret, and redirect_url="https://www.example.com/".
On https://auth.example.com/login/selectprovider/ the user selects facebook or twitter or local, and auth.example.com redirects the user (again) to /login or facebook or twitter, using the client_id and client_secret and redirect_url=https://auth.example.com/twitter or https://auth.example.com/twitter to easily distinguish the three.
Facebook/twitter/local methods will authenticate the user and redirect the browser back to auth.example.com.
auth.example.com will then generate a (Bearer) accessToken for api.example.com and store it together with the user.id into a local database table, with associated scope ("facebook", "twitter" or "local"), put the key (userId) in the browser session and redirect to https://www.example.com/
Now when the user clicks on a link in the WebApp, www.example.com does a GET or POST on api.example.com, providing client_id="www.example.com" client_secret and access_token.
The api.example.com endpoints verify the accessToken, and if ok, execute the API and return the value to www.example.com that renders it to the browser of the user.
Q2 Is above the correct flow, or is there a better way?
If correct, how does api.example.com validate the accessToken at its endpoints?
Should auth.example.com expose a special endpoint for this (eg. /userinfo) that can only be accessed with a client_id="api.example.com" and client_secret? That seems expensive to do for each call, but how else could api.example.com trust the validity of a token (because it expired or the user logged out)?
What's the OAuth2 standards compliant way?
Q3 In passport/OAuth2orize examples, I see 3 ways that authentication is validated:
if (req.user) {...};
if (req.isAuthenticated()) {...};
passport.authenticate('bearer', {session: false);
Q4 What does passport.authenticate('facebook') do exactly?
This information is provided in the strategy.
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);
});
}
));
So this contains the client_id and client_secret. When is this used? Every time passport.authenticate('facebook') is called? Does do the whole redirect to facebook login page, get Authorization code grant and exchange it for an accessToken, store the accessToken internally somehow and keep it until a logout?
It seems unlikely but I don't see how it can actually authenticate the user without all this. And it would be too expensive to do for every API call, so I'm sure it works more efficiently. But I don't know how and studying the source code didn't make it more clear.
Q5 How does *api**.example.com know when the Bearer accessToken included by www.example.com in every API request is not forged or expired?
I assume it has to check it against the auth.example.com service, and that service in turn must check if the facebook/twitter session is still valid too, and refresh tokens using the refreshToken at that moment?
I'm using Node + express to build an API. The idea is to be able to let other developers login and register their app so that i can authorize access to my API endpoints.
exports = passport.use(new FacebookStrategy({
clientID: '999999999',
clientSecret: '999999999',
callbackURL: "http://localhost:3000/auth/facebook/callback"
},function(accessToken, refreshToken, profile, done) {
profile.access_token = accessToken;
db.mongoClient.connect(db.moments, function(err, db){
var user = db.collection('user');
user.find({'facebook':profile.id}).toArray(function(err, docs){
console.log(docs);
})
})
done(null, profile);
}));
I have set this up using the passport facebook strategy. This allows developers to login to a profile page on my app where they are presented with the access_token i got from facebook. I'm using this access_token to allow a connection between my app and their app using the bearer token strategy.
However, i also want to add another layer of security. They should register the domain name that is going to make API calls to my app. This should protect me from developers passing along the token to other developers (did i got that part right?).
The question: How can i check that they are indeed making the request from the registered domain name?
thx,
After your facebook authentication, you know user and you know his registered domain. Then make call from server to some defined script at registered domain. And if indeed it was call from this user then he should return some response which you agreed with him. And if response is ok, then finish authentication (if I correctly remember some payment systems make this verification for online shops).
Or something more sophisticated, after facebook auth, send to registered domain url some temporary token. Then user must send you in next call this temporary token and you exchange it for final token.
To be secure your users should have https when your server call them. Otherwise it is not reliable.
I'm trying to find out how Facebook authentication works when using passport-facebook with node/express.
I'm confused about the callbackURL and the function that follows below.
Can someone explain to me what the difference is between setting a callbackURL (is this where a successful login attempt end up? and the function(accessToken, ...) which also seems to be invoked after logging in.
passport.use(new FacebookStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET,
callbackURL: "http://localhost:3000/auth/facebook/callback"
},
function(accessToken, refreshToken, profile, done) {
User.findOrCreate({ facebookId: profile.id }, function (err, user) {
return done(err, user);
});
}
));
callbackURL is a URL that facebook's web servers themselves will use at the end of the process. Facebook's servers will send a 301 redirect response causing the user's browser to navigate to this URL. So this is essentially a configuration option you are sending to facebook itself, and passport.js is handling the specifics of when and where to send it. When the whole oauth dance is done, the callback function is a way for passport to give control back to your code and say "hey, look it worked. Here's the goodies on the logged-in user", so you can do your findOrCreate. The details inside that function typically vary per-application whereas the oauth dance is always the same. So that's why passport uses a function callback there. It allows you a hook for application-specific or custom logic.