how to integrate passport-facebook and jwt without session? - jwt

I want to use passport-github or facebook login with jwt token, without using saving sessions on the server.
But we have two requests from frontend:
app.get('/auth/facebook',
passport.authenticate('facebook'));
app.get('/auth/facebook/callback',
passport.authenticate('facebook', { failureRedirect: '/login' }),
function(req, res) {
// Successful authentication, redirect home.
res.redirect('/');
});
how to handle the frontend codes?
In normal case, we only have one request
axios.post(`${API_URL}/auth/login`, { email, password })
.then(response => {
cookie.save('token', response.data.token, { path: '/' });
dispatch({ type: AUTH_USER });
window.location.href = CLIENT_ROOT_URL + '/dashboard';
})
.catch((error) => {
errorHandler(dispatch, error.response, AUTH_ERROR)
});
}
so we can save the token locally. but for passport-facebook, we have two requests('/auth/facebook' and '/auth/facebook/callback'). So how to save the token locally?

First of all, I think the GET request will not work. You need to use an a link to trigger the /auth/login.
<a href="http://localhost:5150/auth/facebook">
To send the token to the client, you should redirect to a client page with the jwt stored in cookie.
const token = user.generateJwt();
res.cookie("auth", token);
return res.redirect(`http://localhost:3000/socialauthredirect`);
and at the client landing page extract the jwt and save it to local storage.
class SocialAuthRedirect extends Component {
componentWillMount() {
this.props.dispatch(
fbAuthUser(getCookie("auth"), () => {
document.cookie =
"auth=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
this.props.history.push("/profile");
})
);
}
render() {
return <div />;
}
}

Related

Get token set on API on a SSR page Nextjs

I am using Spotify authentication and in the callback I set the cookie and redirect to another page:
export default async (req, res) => {
const token = await getToken(req.query.code);
res.setHeader('Set-Cookie', cookie.serialize('token', JSON.stringify(token), {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
maxAge: token.expires_in,
sameSite: 'strict',
path: '/',
}));
res.redirect(token ? '/cloner' : '/');
}
On '/cloner' page I do SSR where '/' is the path to the login page:
export async function getServerSideProps(ctx) {
const cookies = nookies.get(ctx);
if (!cookies.token) { // <-- is undefined
return {
redirect: {
destination: '/',
permanent: false,
}
}
}
return {
props: {}
}
}
In the getServerSideProps the token is undefined so is returning me to the login page ('/').
BUUUUUUT, if I check in the site I can see the cookie, and if I write the /cloner manually that page load just right.
If you check in the link below you will see that if you login redirect to login again. But, if you refresh the login page it sends you to the cloner page (in login I have also SSR to redirect to cloner if already login)
https://playlist-cloner.vercel.app/

How could i pass cookies in Axios

I am in a next-js app and my auth token is stored in cookies.
For some raisons i use Swr and Api route to fetch my secured api backend.
i am trying to find a way to put my auth token in all api request.
During login cookie is set
res.setHeader(
'Set-Cookie',
cookie.serialize('token', data.access_token, {
httpOnly: true,
secure: process.env.NODE_ENV !== 'development',
maxAge: data.expires_in, // 1 week
sameSite: 'strict',
path: '/',
}),
);
This is an example of a page using swr fetch
//page/test.ts - example of my test route
const { data, error } = useFetchContent(id);
if (error) {
showError('error');
replace('/');
}
return <DisplayContent content={data} />
This is a swrFetchHook
// fetchContentHook
function useFetchContent(id: string): ContentDetail {
return useSWR<any>(`/api/content/${id}`, fetcherApiRoute);
}
const fetcherApiRoute = (url: string): Promise<any> => {
return axios(url)
.then((r) => r.data)
.catch((err) => {
console.info('error is ', err)
throw err
});
};
export default useFetchContent;
inside api route
export default async (req, res): Promise<ContentDetail> => {
const { id } = req.query;
if (req.method === 'GET') {
const fetchRealApi = await apiAxios(url);
if(fetchRealApi) {
// here depending on result of fetchRealApi i add some other fetch ...
return res.status(200).json({ ...fetchRealApi, complement: comp1 });
}
return res.status(500)
}
return res.status(500).json({ message: 'Unsupported method only GET is allowed' });
};
and finally api axios configuration
const apiAxios = axios.create({
baseURL: '/myBase',
});
apiAxios.interceptors.request.use(
async (req) => {
// HERE i am trying to get token from cookies
// and also HERE if token is expired i am trying to refresh token
config.headers.Authorization = token;
req.headers['Content-type'] = 'application/x-www-form-urlencoded';
return req;
},
(error) => {
return Promise.reject(error);
},
);
export default apiAxios;
I am stuck here because i cant find token during apiAxios.interceptors.request.use...
Did you know what i am doing wrong, and am i on a correct way to handle this behavior ?
To allow sending server cookie to every subsequent request, you need to set withCredentials to true. here is the code.
const apiAxios = axios.create({
baseURL: '/myBase',
withCredentials: true,
});
Nilesh's answer is right if your API is able to authorize requests based on cookies. Also it needs the API to be in the same domain as your frontend app. If you need to send tokens to the API (the one which is in the cookie), then you will need a small backend component often called BFF or Token Handler. It can extract the token from the cookie and put in an Authorization header.
At Curity we've created a sample implementation of such a Token Handler, of which you can inspire: https://github.com/curityio/kong-bff-plugin/ You can also have a look at an overview article of the Token Handler pattern.

Logout of Google IDP with Passport saml

I am using passport-saml to authenticate users via Google IDP(SAML APP)
My SAML Strategy is configured as below
const samlStrategy = new SamlStrategy({
protocol: PROTOCOL,
entryPoint: SSO_URL, // SSO URL (Step 2)
issuer: SP_ENTITY_ID, // Entity ID (Step 4)
path: CALLBACK_PATH, // ACS URL path (Step 4)
cert: IDP_CERT,
logoutUrl: 'https://accounts.google.com/logout',
logoutCallbackUrl: '/signout'
}, function (profile, done) {
done(null, JSON.parse(JSON.stringify(profile)))
})
passport.use(samlStrategy)
Using the Passport SAML Strategy, I am able to login successfully
On Logout, I am logging out of SAML Strategy as below
server.get('/logout', function (req, res) {
try {
req.user.nameID = req.user.nameID;
req.user.nameIDFormat = req.user.nameIDFormat;
samlStrategy.logout(req, function(err, requestUrl){
if(err){
return res.send({ success: false, error: err });
}
req.logout()
req.session=null
req.user=null
return res.redirect(requestUrl);
});
} catch(error) {
return res.send({ success: false, error });
}
})
This is logging me out of all Google accounts that are logged into the browser.
QUESTIONS:
Is there a way to just logout only from the specific Google account that I have used for SAML Strategy?
Logout callback url is also not called

Move to another hbs in ember after the authentication is done

I have an app in which I have include a fb login.I am using ember-simple-auth for authorization and session manganement.I am able to authenticate the user and move to my "feed" hbs .The problem is when I open the app on another tab it is rendering the login page.How do I implement where if the user is authenticated it directly move to "feed" hbs.Similary to facebook,instagram where user login for the first time and after that they are redirect to feed page until they logout.
autheticator.js
const { RSVP } = Ember;
const { service } = Ember.inject;
export default Torii.extend({
torii: service('torii'),
authenticate() {
return new RSVP.Promise((resolve, reject) => {
this._super(...arguments).then((data) => {
console.log(data.accessToken)
raw({
url: 'http://example.com/api/socialsignup/',
type: 'POST',
dataType: 'json',
data: { 'access_token':'CAAQBoaAUyfoBAEs04M','provider':'facebook'}
}).then((response) => {
console.log(response)
resolve({
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
access_token: response.access_token,
// jscs:enable requireCamelCaseOrUpperCaseIdentifiers
provider: data.provider
});
}, reject);
}, reject);
});
}
});
router.js
import Ember from 'ember';
import config from './config/environment';
var Router = Ember.Router.extend({
location: config.locationType
});
Router.map(function() {
this.route('index',{path:'/'});
this.route("aboutus",{path:'/aboutus'});
this.route('feed',{path:'/feed'});
});
export default Router;
You need to use the application-route-mixin.js in the route that will be the first shown after login and authenticated-route-mixin.js for all the routes that need to be logged to see them. Check this example for further information.

how does Passport.js obtains the Profile data using OAuth2 strategy?

In the example of oauth2 strategy usage in the Passport's repo, the following function is presented:
passport.use(new OAuth2Strategy({
authorizationURL: 'https://www.example.com/oauth2/authorize',
tokenURL: 'https://www.example.com/oauth2/token',
clientID: EXAMPLE_CLIENT_ID,
clientSecret: EXAMPLE_CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/example/callback"
},
function(accessToken, refreshToken, profile, done) {
User.findOrCreate({ exampleId: profile.id }, function (err, user) {
return done(err, user);
});
}
));
How does Passport obtains the profile field? is it provided with the token by the oauth endpoint? or does it come from a separate (session-related) request?
When using, for example, the Facebook's oauth API, the user info is loaded automatically with the Passport's Facebook strategy, so I'm trying to figure out how does this happen and how to implement a similar behavior in a custom oauth2 API.
The user profile is typically loaded after the access_token is successfully retrieved:
https://github.com/jaredhanson/passport-oauth2/blob/master/lib/strategy.js#L175
this._oauth2.getOAuthAccessToken(code, { grant_type: 'authorization_code', redirect_uri: callbackURL },
function(err, accessToken, refreshToken, params) {
if (err) { return self.error(self._createOAuthError('Failed to obtain access token', err)); }
self._loadUserProfile(accessToken, function(err, profile) {
if (err) { return self.error(err); }
The function to actually get the user information is often provided by the specific strategy (e.g. Facebook, Twitter, etc)
In Facebook's implementation:
https://github.com/jaredhanson/passport-facebook/blob/master/lib/strategy.js#L137