Appwrite authentication - "createJWT is not a function" error - node.js

I am trying to build a Node.js server-side signup function for user authentication. The data for the user is being sent via "req.body" and the authentication database is provided by Appwrite.
The signup function should:
Create a user with the credentials provided in the request body.
Return the user details, such as the username and email.
Generate and return a token (cookie/JWT)
I am encountering issues with the Appwrite documentation and would appreciate guidance on building this function.
When trying to POST a new user using the Users API, an error of
createJWT is not a function
is produced, and when using the Account API, an error of
User (role: guests) missing scope (account)
is produced.
Here's the code I have:
const sdk = require('node-appwrite')
const client = sdk.Client()
client
.setEndpoint(endpoint)
.setProject(projectId)
.setKey('...')
const users = sdk.Users(client)
async function signup(req, res) {
try {
const { email, username } = req.body
let { password } = req.body
password = await bcrypt.hash(password, SALT_ROUNDS)
const result = await users.createBcryptUser("unique()", email, password, username)
// Create a token
// Combine data
res.send(userWithToken)
} catch (err) {
error('Failed to signup', err)
throw new Error(err)
}
}

The Users API is intended to be used in an admin perspective rather than as a user. You can use the Account API to execute things on behalf of a user, but the JWT token is typically generated client side and passed to the server, where you can call client.setJWT().

Related

What's the best way to add social login (Sign in with Google) to existing email/password app and database?

I want to integrate sign in by google to an app that already has account signup and login.
I followed some youtube tutorial and I now have a working sign in by google working on my frontend. It returns a JWT upon successful log in. Decoding it gives me an object that contains an email, name, family name, pfp, and some other properties that I don't know what they are for.
What do I do with that ?
In my express server I have a register route
router.post("/register", async (req, res, next) => {
try {
// expects {email, password} in req.body
const { password, email } = req.body;
const user = await User.create(req.body);
const token = jwt.sign(
{ id: user.dataValues.id },
process.env.SESSION_SECRET,
{ expiresIn: 86400 }
);
res.json({
...user.dataValues,
token,
});
} catch (error) {
if (error.name === "SequelizeUniqueConstraintError") {
return res.status(401).json({ error: "Email already exists" });
} else if (error.name === "SequelizeValidationError") {
return res.status(401).json({ error: "Validation error" });
} else next(error);
}
});
Login route is similar.
The database I used was postgres with sequelize ORM, User.create(...) basically just creates a user and stores the hashed password to verify later.
As you could see, if they use google auth it wont have a password while regular signup would. Do I just allow User.create to also create a user if password not given? Would that be secure? What is the correct way to go about this?
A user who logs on to your app must
either type their email address and password into your login form, then your app checks the password hash and creates the token = jwt.sign(...). I would recommend that your JWT also contains the email address, preferably in the same format that Google's JWT uses.
or start a Google logon flow, then Google sends your app a JWT. During this flow, no password hash is looked up from your user database, but if the Google email address is not already in your database, it is a new user for whom you must insert a record into your database (only email address, no password).
The JWT should have an iss claim that tells you whether it was issued by your app or by Google. In Google's case, the JWT is signed by Google, and in your /register and /login routes you must verify the signature with jwt.verify using Google's public key (presumably this). (Actually, registration and login don't differ much if you use a third party authentication service like Google's.)
I assume that in both cases you store the JWT in a session cookie
res.cookie("jwt", token, {httpOnly: true});
and every subsequent request must repeat the signature verification of the JWT
try {
var jwt = jwt.verify(req.cookies.jwt, publicKey);
if (jwt.exp <= new Date().getTime() / 1000)
throw "expired";
// Token verification succeeded
} catch(e) {
// Token verification failed
}
(either with your own app's public key or with Google's, depending on the iss). Only after successful verification does the request count as authenticated, and you can then retrieve the user record from your user store based on the email address.
The password (hash) in your use database is thus optional, but even users with a password could use Google for logon.

How to get an idToken that is valid for development from firebase without having to spin up my frontend?

I am working on some firebase functions. This one will check if an user is logged in in firebase first. However this is a bit of a hassle in development. Now I need to login on the frontend first to get the id_token, pass it to my function url, then see the result.
The process I am following is described in the official docs: https://firebase.google.com/docs/auth/admin/verify-id-tokens
node.js
const admin = require('firebase-admin');
admin.initializeApp();
module.exports = function( request, response ) {
if( !request.query.id_token )
response.status(400).json({message: 'id token has not been provided'});
admin.auth()
.verifyIdToken( request.query.id_token )
.then( token => {
// TODO: redirect to payment portal
return response.status(200).json({message: 'Success'});
})
.catch( error => {
return response.status(401).json({message: 'You are currently not logged in as an authorised user'});
})
}
Is there a way to get an id_token that is valid from firebase without having to spin up my frontend? Good and simple alternatives solutions are welcome too.
NOTE: I am using the firebase emulators during development.
Since you're using the Firebase emulators you may create a fake user and retrieve an id token programmatically. The code below creates and logs in a user and returns an id_token that will be accepted by your function.
var firebase = require("firebase/app");
require("firebase/auth");
// Initialize Firebase and connect to the Authentication emulator
var firebaseConfig = {
// Insert Firebase config here
};
firebase.initializeApp(firebaseConfig);
firebase.auth().useEmulator('http://localhost:9099/');
// Create a fake user and get the token
firebase.auth().createUserWithEmailAndPassword("example#example.com", "password")
.then((userCredential) => {
console.log("User created")
});
firebase.auth().signInWithEmailAndPassword("example#example.com", "password")
.then((userCredential) => {
console.log("User logged in")
userCredential.user.getIdToken().then((idToken) => {
console.log(idToken)
});
});

Firebase Authentication Microservice

I am trying to write a REST microservice in Node.js that would deal with user authentication (among some other things) requests coming from different platforms.
What I would like is for the device to remember which user is signed in and keep the session for itself only. What currently happening is that I am able to login only one user at a time; if another user logs in from another device, the new user is returned as the currentUser. It's my first time using Firebase Authentication so I am very confused.
Here's the code for the login endpoint:
async signInUser( req, res, next ) {
var user = firebase.auth().currentUser;
if ( !user) {
var email = req.body.email;
var password = req.body.password;
// sign user in: if login fails, send error message as response
user = await firebase.auth().signInWithEmailAndPassword( email, password)
.catch( function( error) {
res.send( error.message);
});
}
// login successful: send user object as response
res.send( user);
}
Firebase have custom authentication you can pass your user unique id to firebase and genrate token for perticular user so you can able create unique session for different user and you can refer below link
https://firebase.google.com/docs/auth/admin/create-custom-tokens

How to integrate rest api with front end website/app?

I already built out my restful api for logging in and registering, my question is how do I now use this api in my website? Isn't the point of an api to return json to consume? If i were to put a res.redirect() then wouldn't that make the api useless for later on when i want to use the api for say an iOS app?
router.post('/login', async (request, response) => {
// validate
const {error} = loginValidation(request.body)
if (error) return response.status(400).send(error.details[0].message)
const {email, password} = request.body
// check if email doesn't exist
const user = await pool.query('SELECT id, email, password FROM users WHERE email = $1 LIMIT 1', [email])
if(user.rowCount == 0) return response.status(400).send('Wrong email or password')
// password is correct; move on to validating password
const id = user.rows[0].id
const storedEmail = user.rows[0].email
const storedPassword = user.rows[0].password
const validPass = await bcrypt.compare(request.body.password, storedPassword)
if(!validPass) return response.status(400).send('Wrong email or password')
// create and send token to client
const token = jwt.sign({_id: id}, "SOMESECRET")
response.header('auth-token', token).send(token)
})
You could try these ways:
Make API calls from web clients(i.e. web browsers) with Javascript.
Set up a web server and make API calls from the server.

how to save JWT token on client, using Hapi js in node.?

I want to authenticate a user using JWT token. after a successful validation i am creating a jwt token. I have got some where on internet that i have to send this token to client.how can i save this token and how i can send this token to every request or the token will be automatically attached to the request header? if not then how can i attach this token in request header?. I am using Hapi js with node.
below is my code:
var validateUser = function(request, reply) {
var email = request.payload.email;
var userPassword = request.payload.password;
// get user form database
var user = users[email];
// check if exists
if(!user){
var errMsg = 'User not found';
reply.view('login',{errMsg:errMsg});
}
else {
// validate the user
bcrypt.compare(userPassword, user.password, function(err, isValid) {
if(!isValid){
var errMsg = 'Wrong username or password!';
reply.view('login',{errMsg:errMsg});
}
else {
// if user is found and password is right
// create a token
var token = jwt.sign(user.id, process.env.SECRET_KEY);
// I want to send this token to client, and also want to save this token in header of every request.
reply.redirect('/myNotes');
}
});
}
}
1)after the login store token in local storage(client side)
2)add token to request header using http interceptor.
are you using jquery to call the end points then $ajax setUp is the right place.you can get more details from this post https://www.bennadel.com/blog/2131-using-jquery-ajaxsetup-to-accumulate-global-data-parameters-for-ajax-requests.htm.
if you are consuming services directly from Hapi js then use onpreAuth handler.
If you need any help let me know.i am happy to help

Resources