How can I have a Foxx service use base collections for auth operations? For example I want the User management tutorial at https://docs.arangodb.com/3.11/develop/foxx-microservices/guides/authentication-and-sessions/ to use collections "users" and "sessions" instead of "test_users" and "test_sessions", where "test" is the name of my mountpoint.
I want to run multiple services all working off the same base collections. But if I go with whats given in the tutorials, I end up with auth collections and routes which are specific to a service, which doesnt males much sense to me.
My setup.js is;
'use strict';
const db = require('@arangodb').db;
const sessions = module.context.collectionName('sessions');
const users = module.context.collectionName('users');
if (!db._collection(sessions)) {
db._createDocumentCollection(sessions);
}
if (!db._collection(users)) {
db._createDocumentCollection(users);
}
db._collection(users).ensureIndex({
type: 'hash',
fields: ['username'],
unique: true
});
and my index.js is;
'use strict';
const joi = require('joi');
const createAuth = require('@arangodb/foxx/auth');
const createRouter = require('@arangodb/foxx/router');
const sessionsMiddleware = require('@arangodb/foxx/sessions');
// const db = require('@arangodb').db;
const auth = createAuth();
const router = createRouter();
const users = db._collection('users');
const sessions = sessionsMiddleware({
storage: module.context.collection('sessions'),
transport: 'cookie'
});
module.context.use(sessions);
module.context.use(router);
// continued
router.post('/signup', function (req, res) {
const user = {};
try {
user.authData = auth.create(req.body.password);
user.username = req.body.username;
user.perms = [];
const meta = users.save(user);
Object.assign(user, meta);
} catch (e) {
// Failed to save the user
// We'll assume the uniqueness constraint has been violated
res.throw('bad request', 'Username already taken', e);
}
req.session.uid = user._key;
req.sessionStorage.save(req.session);
res.send({success: true});
})
.body(joi.object({
username: joi.string().required(),
password: joi.string().required()
}).required(), 'Credentials')
.description('Creates a new user and logs them in.');
I tried using const users = db._collection('users');
instead of const users = module.context.collection('users');
but that throws swagger api errors.
to achieve that you need to change the assignment of collection names from module.context.collectionName('nameOfCollection')
to 'nameOfCollection'
in all files, because module.context.collectionName
prefixes string with name of service
so
setup.js
const sessions = 'sessions';
const users = 'users';
index.js
const users = db._collection('users');
const sessions = sessionsMiddleware({
storage: 'sessions',
transport: 'cookie'
});
however, that approach is antipattern for case when more services need access to same underlying collections (for example teardown of one service can delete those collections for other services).
for that case you should utilize dependencies, only your auth service should have access to its own collections and other services should have auth service as dependency and access auth data through auth service.
auth service needs to have
in manifest.json
"provides": {
"myauth": "1.0.0"
}
in index.js or what file you pointing as main
in manifest.json
module.exports = {
isAuthorized (id) {
return false; // your code for validating if user is authorized
}
};
consuming service needs to have
in manifest.json
"dependencies": {
"myauth": {
"name": "myauth",
"version": "^1.0.0",
"description": "Auth service.",
"required": true
}
}
and then you can register it and call it
const myauth = module.context.dependencies.myauth;
if (myauth.isAuthorized()) {
// your code
} else {
res.throw(401);
}
for further steps in terms of authorization of requests check how to use Middleware and Session middleware
god speed