Skip to content

Instantly share code, notes, and snippets.

@gabrielepalma
Created January 5, 2019 04:16
Show Gist options
  • Save gabrielepalma/e6550d4b5529bff014e957e79905d8fa to your computer and use it in GitHub Desktop.
Save gabrielepalma/e6550d4b5529bff014e957e79905d8fa to your computer and use it in GitHub Desktop.
Authentication
func loginUser(_ request: Request) throws -> Future<AuthorizedUser>
{
let minimumTimeToLiveForRefreshToken : Double = 60 * 60 * 24 * 30 // One month
let user = try request.requireAuthenticated(User.self)
guard let userId = user.id else {
throw Abort(HTTPResponseStatus.internalServerError)
}
let accessTokenString = try user.createJwt(usage: JWTConfig.AccessToken.usage, expiration: JWTConfig.AccessToken.expiration).0
let promise = request.eventLoop.newPromise(of: AuthorizedUser.self)
DispatchQueue.global().async {
// Decode the body
guard let decodedBody = try? request.content.decode(LoginBody.self).wait() else {
promise.fail(error: Abort(HTTPResponseStatus.badRequest))
return
}
let refreshTokenString : String
// If a token was given, do token cleaning and reissuing operations, otherwise just create a new one
if let givenTokenString = decodedBody.refreshToken, let data = givenTokenString.data(using: .utf8),
let givenToken = try? JWT<SublimatePayload>(unverifiedFrom: data)
{
// Delete, if existing, the refresh token that was replaced by the one used in this requet
// This is now safe as we have proof the new refresh token was successfully received by the client
try? RefreshToken.query(on: request).filter(\RefreshToken.issuedToReplace == givenToken.payload.tokenId.value).delete().wait()
// Check if given token is about to expire and we want to replace it
let timeToLive = givenToken.payload.exp.value.timeIntervalSince1970 - Date().timeIntervalSince1970
if timeToLive < minimumTimeToLiveForRefreshToken {
// Create and save the new token
guard let result = newToken(for: user, on: request, toReplace: givenTokenString) else {
promise.fail(error: Abort(HTTPResponseStatus.internalServerError))
return
}
refreshTokenString = result
}
else {
// We don't need to reissue the refresh token, we return back the old one, no changes in database
refreshTokenString = givenTokenString
}
}
else {
// Create and save the new token
guard let result = newToken(for: user, on: request, toReplace: nil) else {
promise.fail(error: Abort(HTTPResponseStatus.internalServerError))
return
}
refreshTokenString = result
}
promise.succeed(result: AuthorizedUser(userId: userId.uuidString, username: user.username, refreshToken: refreshTokenString, accessToken: accessTokenString))
}
return promise.futureResult
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment