Async Authentication
Real deployments rarely have hard-coded credentials — permissions live in a database. The
whole request pipeline is async-aware, so you can await inside authenticate and even
resolve the repository directory asynchronously.
Await inside the user callback
The callback passed to user() may be async. Do your lookup, then call next():
import { Git } from "@batchfy/node-git-server"
const repos = new Git("./repos", {
authenticate: ({ type, repo, user }, next) => {
user(async (username, password) => {
try {
await checkPermission({ username, password, repo, action: type })
await next()
} catch (error) {
await next(error)
}
})
},
})checkPermission is your own function — query a users table, verify a password hash, and
check whether the user may fetch or push this repository:
export async function checkPermission({ username, password, repo, action }) {
const user = await db.user.findByName(username)
if (!user || !(await verifyHash(password, user.passwordHash))) {
throw new Error("invalid credentials")
}
const canWrite = await db.access.canWrite(user.id, repo)
if (action === "push" && !canWrite) {
throw new Error("write access denied")
}
}Because the check throws on failure, the catch turns it into next(error) — a clean
401 for the git client.
Async repository resolution
The first argument to new Git() may be a function that returns a
string or a Promise<string>. Use it to resolve a repository path from a database —
for example mapping a username/project slug to a project id on disk:
const repos = new Git(
async (repo) => {
const projectId = await db.project.resolveId(repo)
return `/srv/git/${projectId}.git`
},
{
autoCreate: false,
authenticate: ({ type, repo, user }, next) => {
user(async (username, password) => {
try {
await checkPermission({ username, password, repo, action: type })
await next()
} catch (error) {
await next(error)
}
})
},
}
)The resolver is awaited everywhere the server needs a path, so a single async source of truth drives both routing and storage.
Related async methods
These Git methods are async and honour the resolver:
await repos.exists(repo)→Promise<boolean>await repos.list()→Promise<string[]>await repos.create(repo)→Promise<void>
See the Git API reference for details.