I'm doing socials login with firebase (facebook and google is ok) but have problem with microsoft
I used expo-auth-session to get the response.params.code from Azure
if (type === 'facebook') {
requestConfig = Facebook.useAuthRequest({
clientId: DEFAULT_AUTH_CONFIG.facebookAppId,
});
} else if (type === 'microsoft') {
const microsoftConfig = {
clientId: DEFAULT_AUTH_CONFIG.msClientId,
scopes: ['openid', 'profile', 'email'],
redirectUri: makeRedirectUri({
scheme: DEFAULT_AUTH_CONFIG.msScheme,
}),
tenantId: DEFAULT_AUTH_CONFIG.msTenantId,
grantType: 'authorization_code',
};
const discovery = useAutoDiscovery(
`https://login.microsoftonline.com/${microsoftConfig.tenantId}/v2.0`,
);
requestConfig = useAuthRequest(microsoftConfig, discovery);
}
const [request, response, promptAsync] = requestConfig;
and then use exchangeCodeAsync to get the idToken + accessToken
const { accessToken, idToken } = await exchangeCodeAsync(
{
code,
clientId: DEFAULT_AUTH_CONFIG.msClientId,
redirectUri: makeRedirectUri({
scheme: 'https://cbot-dev.firebaseapp.com/__/auth/handler',
}),
scopes: ['openid', 'profile', 'email'],
extraParams: { code_verifier: request.codeVerifier },
},
{
tokenEndpoint: `https://login.microsoftonline.com/${DEFAULT_AUTH_CONFIG.msTenantId}/oauth2/v2.0/token`,
},
);
Next I use signInWithCredential as shown below but get wrong providerId or credential error If anyone has encountered this problem, please help me
const provider = new OAuthProvider('microsoft.com');
const credential = provider.credential({
idToken,
accessToken,
});
signInWithCredential(getAuth(), credential).catch((error) => {
console.log(error);
toast.error(formatError(error));
});
error:
Firebase: Invalid IdP response/credential: http://localhost?&id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImpTMVhvMU9XRGpfNTJ2YndHTm...
Related
I'm using bell (https://www.npmjs.com/package/bell) for authentication plugin. I used version 10.0.0.
I've setup the configuration in Apple developer site. I got this issue:
ERROR secretOrPrivateKey must be an asymmetric key when using ES256
Here is my apple authentication plugin for hapi
const jwt = require('jsonwebtoken')
const jwksClient = require('jwks-rsa')
const consola = require('consola')
const config = require('../config/server')
const client = jwksClient({
jwksUri: 'https://appleid.apple.com/auth/keys',
timeout: 30000
})
function getSecretKey () {
const claims = {
iss: config.authAppleSecretTeamId,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 86400 * 180,
aud: 'https://appleid.apple.com',
sub: config.authAppleId
}
const token = jwt.sign(claims, config.authAppleSecretPrivateKey, {
algorithm: 'ES256',
keyid: config.authAppleSecretKeyId
})
return token
}
function getApplePublicKey (kid) {
return new Promise((resolve) => {
client.getSigningKey(kid, (_, key) => {
const publicKey = key.getPublicKey()
resolve(publicKey)
})
})
}
const appleProvider = {
auth: 'https://appleid.apple.com/auth/authorize',
token: 'https://appleid.apple.com/auth/token',
name: 'apple',
protocol: 'oauth2',
useParamsAuth: true,
profile: async (credentials, params) => {
const { header } = jwt.decode(params.id_token, { complete: true })
const publicKey = await getApplePublicKey(header.kid)
const resp = jwt.verify(params.id_token, publicKey)
if (config.environment !== 'production') {
console.log('appleProvider -> params, header, resp : ', params, header, resp)
}
const { sub, email, name } = resp
credentials.profile = {
id: sub,
email,
name: {
first: name.firstName || '',
last: name.lastName || ''
}
}
}
}
module.exports.plugin = {
name: 'auth-apple',
register: (server, options) => {
const strategy = {
provider: appleProvider,
providerParams: { response_mode: 'form_post' },
scope: ['name', 'email'],
password: config.authApplePassword,
clientId: config.authAppleId,
clientSecret: getSecretKey(),
location: config.baseUrl,
forceHttps: true,
isSecure: true
}
if (['development', 'localtest'].includes(config.environment)) {
consola.log(`Un-setting https for Apple auth strategy in ${config.environment}`)
delete strategy.location
delete strategy.forceHttps
strategy.isSecure = false
}
server.auth.strategy('apple', 'bell', strategy)
}
}
Also bell doesn't have default provider for Apple sign-in, we have to write it.
Any suggestion or guidance will be appreciated
I have used the Vue-Authenticate plugin for the social login and this is my configuration for the Github Login
providers: {
github: {
clientId: 'my Id',
redirectUri: 'https://' + process.env.PROJECT_DOMAIN,
responseType: 'token',
authorizationEndpoint: 'https://github.com/login/oauth/authorize',
},
},
And in the method through which is calling the method after authentication is
authenticate(provider) {
const this_ = this
this.$auth.authenticate(provider).then(function () {
const token = this_.$auth.getToken()
if (provider === 'github') {
const options = {
headers: {
Authorization: 'token ' + token,
},
}
this_.$http
.post('https://api.github.com/user', options)
.then(function (response) {
if (response.status === 200) {
const { email, name, picture } = response.data
const data = {
email,
name,
image: picture.data.url,
}
this_.createOAuth2User(data, provider)
}
})
.catch((error) => {
console.log(error)
})
}
})
},
I am able to receive an access token after successful authentication but when I try to use that token to access the user details and hit the https://api.github.com/user API I am getting 401 error. So is there something I am missing while authentication with github?
I am using facebook and google oauth2 login using passport js, with this flow
User clicked the login button
Redirects to facebook/google auth page (depending on what login the user chooses)
The auth page redirects back to a callback page (/auth/callback/[provider])
A passport express middleware will catch it to parse some data and then send it to a remote api of myown to sign the user in
The auth remote api will send a response back consisting the user token
A custom express middleware will catch the response to set cookie on the server
the express chain ends by route it to /profile (cookie with token is set on the browser)
/profile will then checks if there is a token, if there is not: it will redirect to /
Doing this flow on facebook login is fine, the user is successfully redirected to /profile, with all of its data and token, the google oauth2 login however seems to be doing the redirect to /profile then setting the token (step #7 then #6), so everytime the user is using google oauth2 login, its always gonna be redirected back to / since by the time it arrives at /profile, it doesnt have the token
here's the code on the above's flow
#./server.js
const express = require('express')
const next = require('next')
const Passport = require('./server/middleware/passport')
const Api = require('./server/api')
const port = parseInt(process.env.PORT, 10)
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app
.prepare()
.then(() => {
const server = express()
// ... other unrelated things
server.use(Passport.initialize())
Api.passport.facebook(server)
Api.passport.facebookCallback(server)
Api.passport.google(server)
Api.passport.googleCallback(server)
// ... other unrelated things
server.all('*', (req, res) => handle(req, res))
server.listen(port, (error) => {
if (error) throw error
// ... other unrelated things
})
})
#./server/api.js
const Passport = require('middleware/passport')
function setCookie(req, res, next) {
res.cookie('token', req.user.auth.token, {
httpOnly: true,
sameSite: 'strict',
path: '/',
secure: process.env.NODE_ENV !== 'development',
})
next()
}
function facebook(app) {
return app.get('/auth/facebook', (req, res, next) => {
Passport.authenticate('facebook', {
scope: ['email', 'public_profile']
})(req, res, next)
})
}
function facebookCallback(app) {
return app.get(
'/auth/callback/facebook',
Passport.authenticate('facebook', { session: false, failureRedirect: '/' }),
setCookie,
(req, res) => {
res.redirect('/profile')
},
)
}
function google(app) {
return app.get('/auth/google', (req, res, next) => {
Passport.authenticate('google', {
scope: [
'https://www.googleapis.com/auth/userinfo.email ',
'https://www.googleapis.com/auth/userinfo.profile ',
],
prompt: 'consent',
authType: 'rerequest',
accessType: 'offline',
})(req, res, next)
})
}
function googleCallback(app) {
return app.get(
'/auth/callback/google',
Passport.authenticate('google', { failureRedirect: '/', session: false }),
setCookie,
(req, res) => {
res.redirect('/profile')
},
)
}
module.exports = {
passport: {
facebook,
facebookCallback,
google,
googleCallback,
}
}
#./server/middleware/passport.js
const axios = require('axios')
const passport = require('passport')
const GoogleStrategy = require('passport-google-oauth20').Strategy
const FacebookStrategy = require('passport-facebook').Strategy
passport.serializeUser((user, done) => {
done(null, user)
})
passport.deserializeUser((obj, done) => {
done(null, obj)
})
function verifyCallback(req, ... , done) {
process.nextTick(async () => {
try {
const options = {
baseURL: baseUrl, // My remote api url
method: 'POST',
url: '/auth/signin',
headers: {
'Content-Type': 'application/json',
},
data: JSON.stringify({
// email, fullname, etc
}),
}
const response = await axios(options)
return done(null, response.data)
} catch (error) {
const { response } = error
return done(JSON.stringify(response.data, null, 2), null)
}
})
}
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: callbackURLGoogle,
passReqToCallback: true,
}, verifyCallback))
passport.use(new FacebookStrategy({
clientID: process.env.FACEBOOK_CLIENT_ID,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
callbackURL: callbackURLFacebook,
enableProof: true,
profileFields: ['id', 'name', 'email', 'picture.type(large)'],
passReqToCallback: true,
}, verifyCallback))
module.exports = passport
I console.log() things, just to figure out if it falls to the correct sequence of flow, the console doesn't seem to log anything suspicious, is there's something i am missing here?
PS: i am also using next js with custom server
I was facing the same problem and was able to send cookies by using custom callback.
router.get('/google/callback', (req, res) => {
passport.authenticate('google', {session: false, failureRedirect:'/auth/google/failure'},
async(err, user) => {
// You can send cookies and data in response here.
})(req, res)
})
Please refer custom callback section in documentation for explanation.
In my projects, i have integrated the packages "react-native-app-auth" with strava to authenticate.
const openStravaApp = async () => {
const config = {
clientId: '62069',
clientSecret: '795dad2fc3d5f3ec9277b6a84f1f49cd7dcb324e',
redirectUrl: 'com.exam://com.exam',
serviceConfiguration: {
authorizationEndpoint: 'https://www.strava.com/oauth/mobile/authorize',
tokenEndpoint:
'https://www.strava.com/oauth/token?client_id=62069&client_secret=795dad2fc3d5f3ec9277b6a84f1f49cd7dcb324e',
},
scopes: ['activity:read_all'],
};
const result = await authorize(config);
};
But I got . What did I do wrong
Why my jwt token doesn't expire after 1 hour?
I've noticed that it doesn't expire when I forgot to logout my account in my admin panel that I created in vuejs with vuex.
here is my API that I created in ExpressJS using bcrypt and express-jwt for token.
router.post('/login', (req, res) => {
let sql = "SELECT * FROM AUTHENTICATION WHERE email = ?";
myDB.query(sql, [req.body.email, req.body.password], function (err, results) {
if (err) {
console.log(err);
} else {
if (!results) {
res.status(404).send('No user found.')
} else {
try {
let passwordMatched = bcrypt.compareSync(req.body.password, results[0].password);
if (passwordMatched) {
// Passwords match
let token = jwt.sign({ id: results.id }, config.secret, {
expiresIn: '1h'
});
res.status(200).send({ auth: true, token: token, user: results });
} else {
//Password doesn't match
return res.status(401).send({ auth: false, token: null });
}
} catch (error) {
res.send({ Success: false })
}
}
}
})
});
here's my login in vuex where I received the token from my backend.
import axios from 'axios';
const state = {
status: '',
token: localStorage.getItem('token') || '',
user: {}
};
const getters = {
isLoggedIn: state => !!state.token,
authStatus: state => state.status,
};
const mutations = {
auth_request(state) {
state.status = 'loading'
},
auth_success(state, token, user) {
state.status = 'success'
state.token = token
state.user = user
},
auth_error(state) {
state.status = 'error'
},
logout(state) {
state.status = ''
state.token = ''
},
};
const actions = {
login({ commit }, user) {
return new Promise((resolve, reject) => {
commit('auth_request')
axios({ url: 'http://localhost:9001/login/login', data: user, method: 'POST' })
.then(resp => {
const token = resp.data.token
const user = resp.data.user
localStorage.setItem('token', token)
// Add the following line:
axios.defaults.headers.common['Authorization'] = token
commit('auth_success', token, user)
resolve(resp)
})
.catch(err => {
commit('auth_error')
localStorage.removeItem('token')
reject(err)
})
})
}
};
EDIT: Added vuejs code for login
thanks for the help guys!
Your JWT token is just an encoded + signed JSON with relevant fields such as expiresIn, iat.
While it may contain the expiresIn field, it does not mean that the backend server will honour it.
Logic needs to be written in the backend server to parse the timestamp, do comparison with the current time to determine whether it has expired. If it is expired, the backend should return a response code of 401 Unauthorized to tell the frontend (your Vue client) that the token is no longer valid.
What you can do is to put the expiry-checking logic in a middleware to look into the request headers' Authorization field.