this my routes code
const Joi = require('joi')
const handler = require('../handler/get-request')
const route = {
method: 'POST',
path: '/IB',
options: {
tags: ['api', 'IB', 'request'],
description: 'Request New User IB',
notes: 'It will return new user IB data',
validate: {
payload: {
data: Joi.object().keys({
cifNo: Joi.string().min(5).max(45).required(),
userId: Joi.string().min(5).max(45).required(),
deviceInfo: Joi.string().min(3).max(45).required()
})
}
},
plugins: {
'hapi-swagger': {
responses: {
'200': {
description: 'Success'
}
}
}
},
auth: 'ib'
},
handler
}
module.exports = route
and this is my code where i registered the plugin hapi-auth-jwt
await server.register(require('hapi-auth-jwt2'))
server.auth.strategy('ib', 'jwt', {
key: config.internalServiceAccessToken,
validate: async function (decoded, request) {
// See https://github.com/dwyl/hapi-auth-jwt2
// provides checking for invalidated token after user logout
request.auth.decoded = decoded
const user = await request.server.methods.services.ib.auth.findUser(decoded.username)
return { isValid: user, credentials: decoded }
},
verifyOptions: { algorithms: ['RS256'] }
})
when i hit my routes, i got this error message, "Error: Missing Authentication".
Can someone explain me why? and help me to fix this error. Big Thanks!
Related
I have used next-auth for Authentication in my next.js project and have deployed it on AWS server using DOcker. I am getting "http://localhost:3000/api/auth/error?error=Something%20went%20wrong!%20Please%20try%20again%20later." in responce of network everytime when I try to login or register and on all the pages where I have uset nextauth.
This is my nextauth code:
[...nextauth.js]
import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import { API_BASE_URL } from '../../../utils/constants';
export default NextAuth({
providers: [
CredentialsProvider({
id: 'credentials',
name: 'Busfabrik',
credentials: {
email_id: {
label: 'email',
type: 'email',
},
password: { label: 'Password', type: 'password' }
},
async authorize(credentials, req) {
const payload = {
email_id: credentials.email_id,
password: credentials.password,
isadmin: !!credentials.isadmin
};
const res = await fetch(API_BASE_URL + '/users/login', {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'Content-Type': 'application/json'
},
});
const user = await res.json();
// console.log('user', user);
// If error and we don't have user data, return error
if (!res.ok) {
throw new Error(user.exception);
}
// If no error and we have user data, return it
if (res.ok && user.success) {
return user;
} else {
// Return error if user data could not be retrieved
throw new Error(user.msg);
}
},
}),
// ...add more providers here
],
secret: process.env.JWT_SECRET,
callbacks: {
async jwt({ token, user }) {
// console.log('jwt user', user)
if (user && user.success) {
return {
...token,
accessToken: user.payload.token,
userData: user.payload
};
}
return token;
},
async session({ session, token }) {
// console.log('session', session);
// console.log('session token', token);
session.accessToken = token.accessToken;
session.user = token.userData;
return session;
},
},
theme: {
colorScheme: 'auto', // "auto" | "dark" | "light"
brandColor: '', // Hex color code #33FF5D
logo: '/vercel.svg', // Absolute URL to image
},
// Enable debug messages in the console if you are having problems
debug: process.env.NODE_ENV === 'development',
});
Can someone suggest or have aced the same issue? If Yes, then please guide me on this. I an stuck here from a long time and not able to find the solution.
I am trying to make sure that the front-end of my app will display the error that I want it to display. I am purposely trying to create a user that already exists and therefore show my custom User already exists. Please log in. error.
It shows in postman when sending a request to the same endpoint, but at the front-end, the response just shows the following and not the actual error message I defined:
Response {type: 'cors', url: 'http://localhost:8000/api/user/create', redirected: false, status: 409, ok: false, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 409
statusText: "Conflict"
type: "cors"
url: "http://localhost:8000/api/user/create"
[[Prototype]]: Response
The createUser controller:
export const createUser = async (req: Request, res: Response) => {
const { email, password } = req.body;
const existingUser = await User.findByEmail(email);
if (existingUser) {
return res.status(409).send('User already exists. Please log in.');
}
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = new User(email, hashedPassword);
const saveToDb = await newUser.saveToDb();
if (!saveToDb) {
return res.status(500).send('Could not insert user into the database.');
}
const token = newUser.signToken();
res.status(201).json({ token, id: saveToDb.insertedId });
};
The front-end submission:
const onSubmit: SubmitHandler<CreateAccountFormInputs> = async (formData) => {
try {
setLoading(true);
const res = await fetch('http://localhost:8000/api/user/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
});
console.log(res); // output shown above
if (!res.ok) {
setError(`HTTP error: ${res.status}`);
return;
}
navigate('/login');
} catch (err: any) {
setError(err.message);
} finally {
setLoading(false);
}
}
Inside the if (!res.ok) block, I want to set the error to the custom message that should be returned by the API. But I can't set it if it's not returned.
Does anyone know what I'm doing wrong here?
In our project we need to send notification to many users (even the app is not open in the browser)
Also some times we should send a specific notification just for a group of users not all of them.
And i know, I can do it with firebase cloud message
I know a little about web-push module that use fcm itself, but I am wondering if I can use it instead of fcm?is it posible to config web-push to send notification to a group of users or sending notification for all users in on call?
Can anyone help me in this regard and let me know about the main diffrence between fcm and web-push and which is better or I should use? thanks in advance
//using web-push to notify
//back-end with nod.js:
const webpush = require('web-push');
const vapidKeys = {
publicKey: '\<My_PUBLIC_KEY\>',
privateKey: '\<My_PRIVATE_KEY\>'
};
// get client subscription config from db
const subscription = {
endpoint: '',
expirationTime: null,
keys: {
auth: '',
p256dh: '',
},
};
const payload = {
notification: {
title: 'Title',
body: 'This is my body',
icon: 'assets/icons/icon-384x384.png',
actions: \[
{ action: 'bar', title: 'Focus last' },
{ action: 'baz', title: 'Navigate last' },
\],
data: {
onActionClick: {
default: { operation: 'openWindow' },
bar: {
operation: 'focusLastFocusedOrOpen',
url: '/',
},
baz: {
operation: 'navigateLastFocusedOrOpen',
url: '/',
},
},
},
},
};
const options = {
vapidDetails: {
subject: '',
publicKey: vapidKeys.publicKey,
privateKey: vapidKeys.privateKey,
},
TTL: 60,
};
// send notification
webpush.sendNotification(subscription, JSON.stringify(payload), options)
.then((_) =\> {_
console.log('SENT!!!');
console.log();
})
.catch((_) =\> {_
console.log();
});
I use fcm for my notifications as it allows me to send my notifications to an array containing multiple user notification token:
const axios = require('axios');
async function sendNotification({
token,
sender,
requestId,
amount,
}) {
try {
const data = {
notification: {
body: `Hi, Please confirm payment of ${amount} from ${sender} to be charged from your account`,
title: 'Account request',
click_action: 'Account_request',
},
data: {
sender_phone_number: sender,
amount,
body: 'Test',
title: 'MyMoney',
request_id: requestId,
category: 'Account_request',
},
to: token,
sound: 'default',
category: 'Account_request',
};
const resp = await axios.post('https://fcm.googleapis.com/fcm/send', data, {
headers: {
Authorization: 'key=AuthorizationKey',
},
});
// If notification failed, log error
if (resp.data.failure) {
throw new Error('Failed to send notification');
}
} catch (error) {
console.error(error);
}
}
module.exports = {
sendNotification
};
The token can be:
const token = ["firebaseToken1", "firebaseToken2", "firebaseToken3"]
How to get logged in user in express app. I want to know witch user create post. This is my Post.js model:
const postsSchema = mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User',
},
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
image: {
type: String,
required: true,
},
category: {
type: String,
required: true,
},
numLikes: {
type: Number,
required: true,
default: 0,
},
comments: [commentSchema],
},
{
timestamps: true,
}
);
This is my authUser function where i log in user with email and password:
const authUser = async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (user && (await user.matchPassword(password))) {
res.json({
_id: user._id,
name: user.name,
email: user.email,
isAdmin: user.isAdmin,
token: generateToken(user._id),
});
} else {
res.status(401);
throw new Error('Invalid email or password');
}
};
generateToken function is JWT:
import jwt from 'jsonwebtoken';
const generateToken = id => {
return jwt.sign({ id }, 'abc123', {
expiresIn: '30d',
});
};
export default generateToken;
When i create post i want to know user who created it, this is my create post function:
const createPost = async (req, res) => {
const post = new Post({
user: req.user._id,
title: 'Sample Title',
description: 'Sample Desc',
image: '/images/sample.jpeg',
category: 'Sample Category',
numLikes: 0,
});
const createPost = await post.save();
res.status(201).json(createPost);
};
When i try to create post i got this error in console:
UnhandledPromiseRejectionWarning: TypeError: Cannot read property '_id' of undefined.
I can log in with postman, i can register, i can get user by id. How to tell my app Hey i am logged in user and have access to req.user object
You need to have the client send the token back to you, which you then validate (typically via a middleware affecting some section of endpoints so you don't have to call a validation function in individual endpoints).
If instead, express is also your front end, then you need to use a library like express-session https://www.npmjs.com/package/express-session to manage cookies. A good example is available on their page:
// Use the session middleware
app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
// Access the session as req.session
app.get('/', function(req, res, next) {
if (req.session.views) {
req.session.views++
res.setHeader('Content-Type', 'text/html')
res.write('<p>views: ' + req.session.views + '</p>')
res.write('<p>expires in: ' + (req.session.cookie.maxAge / 1000) + 's</p>')
res.end()
} else {
req.session.views = 1
res.end('welcome to the session demo. refresh!')
}
})
Otherwise you've sent the token to client and done nothing with it.
Do you need of a middleware like this:
module.exports = (req, res, next) => {
// Authorization token example: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWQiOiIxIiwiaWF0IjoxNTE2MjM5MDIyfQ.dYo0kOIhum5mMTRV8CAn8gQ_6aqoDQLE--vCZD4E-fg
const { authorization } = req.headers
if (!authorization) return res.send({ message: 'Token not provided', code: 400 })
const [ schema, token ] = authorization.split(' ')
if (schema !== 'Bearer') return res.send({ message: 'Token is bad formated', code: 400 })
if (!token) return res.send({ message: 'Invalid token', code: 400})
jwt.verify(token, 'abc123', (error, decoded) => {
if (error) return res.send({ message: error.message, code: 401})
req.userId = decoded.id
})
next()
}
Hope this is helpful for you.
The first thing you should do is to send token back to the client or attach cookies to your response.
After which you set up a middleware that will check cookies or token in your case using jwt.verify(token, jwtSecret). That will return the id and all other things you stored in the token, then you then store them in req.user, where you will be able to access the details later.
//if you stored token in cookies -
const {accessToken} = req.signedCookies
const payload = isTokenValid(accessToken) //verify the token
req.user = payload.user;
return next();
//if you stored in auth header
const bearerToken = req.headers.authorization
//bearerToken = "Bearer token"
const token = bearerToken.split(" ").join(",")[1]
//verify the token using jwt
const payload = isTokenValid(token)
req.user = payload
return next()
I'm receiving a 422 Unprocessable Entity, invalid inputs error when making a fetch POST request. This resulted in an empty object {} in my Request Payload.
I've done the following checks. Please take a look and kindly guide me in the right direction.
• checked post-routes
router.post(
'/',
[
check('location').not().isEmpty(),
check('caption').not().isEmpty()
],
postsControllers.createPost
);
• checked posts-controller, extracting correct attributes from body
const { userId, location, caption } = req.body;
const createdPost = new Post({
userId,
location,
imageUrl: 'abc.jpeg',
caption,
})
• checked if managing userId in front-end auth-context
// auth-context
export const AuthContext = createContext({
isLoggedIn: false,
userId: null,
login: () => {},
logout: () => {}
});
// App.js
const login = useCallback((uid) => {
setIsLoggedIn(true);
setUserId(uid);
}, []);
const logout = useCallback(() => {
setIsLoggedIn(false);
setUserId(null);
}, []);
• checked if user property is mapped to user object in signup and login
// signup action of users-controllers
res.status(201).json({ user: createdUser.toObject({ getters: true })});
// login action of users-controllers
res.json({ message: 'Logged in!', user: existingUser.toObject({ getters: true })});
• checked if url, request, body and headers are included when sending request in new post
// New Post
<Formik
initialValues={{ location: '', caption: ''}}
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting }) => {
try {
fetch('http://localhost:5000/api/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
userId: auth.userId,
email: values.email,
password: values.password
})
)
history.push('/');
} catch (err) {}
}}