I'm new to Vapor and I've implemented register and login routes. Register works fine. Every time I call the login route it seems to have a problem. Every time, I try to login with a registered user using Basic Auth it just returns 401. Attaching my code below.
App user model:
extension AppUser: ModelAuthenticatable {
static let usernameKey = \AppUser.$email
static let passwordHashKey = \AppUser.$passwordHash
func verify(password: String) throws -> Bool {
try Bcrypt.verify(password, created: self.passwordHash)
}
}
extension AppUser: JWTPayload {
func verify(using signer: JWTSigner) throws {
}
}
Routes configuration:
//MARK: Unprotected API
let unprotectedApi = app.routes
try unprotectedApi.register(collection: AppUserController.Unprotected())
//MARK: Password Protected API
let passwordProtectedApi = unprotectedApi.grouped(AppUser.authenticator())
try passwordProtectedApi.register(collection: AppUserController.PasswordProtected())
login logic:
extension AppUserController.PasswordProtected: RouteCollection {
func login(req: Request) throws -> EventLoopFuture<Response> {
let user = try req.auth.require(AppUser.self)
let token = try req.jwt.sign(user)
let loginResponse = AppUserLoginResponse(user: user.response, accessToken: token)
return DataWrapper.encodeResponse(data: loginResponse, for: req)
}
func boot(routes: RoutesBuilder) throws {
routes.post(Endpoint.API.Users.login, use: login)
}
}
Your login
route as it stands is returning 401 because you have included it in the protected group, which requires the user to be logged in already. It would normally be unprotected. You need some code to do the logging in. This function assumes the user is identified by an email address and has supplied a password somehow:
private func loginExample( email: String, password: String, on: req Request) -> EventLoopFuture<Bool> {
return AppUser.query(on: req).filter(\.$email == email).first().flatMap { user in
// user will be nil if not found, following line test for this
if let user = user {
// user was identified by email
if try! user.verify(password: password) {
// password matches what is stored
request.auth.login(user)
// login has succeeded
return true
}
}
// login has failed - because either email did not match a user or the password was incorrect
return false
}
}
I've kept it simple by forcing the try
in the call to verify (avoiding do-catch, etc.). You need to use something like this code in your login route, perhaps decoding the email and password from an HTML form.