Created
January 5, 2019 04:16
-
-
Save gabrielepalma/e6550d4b5529bff014e957e79905d8fa to your computer and use it in GitHub Desktop.
Authentication
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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