DEV Community

Discussion on: Using JWTs for Authentication in RESTful Applications

Collapse
 
convene143 profile image
Conven • Edited

Hi Perry , It's very useful article.
need help to set httpOnly flag to an existing response cookie.
Problem is jwt value is visible to client on browser to restrict we need to add security flag to cookies I couldn't find the right cookie Could you please help out me ,,
Here is the code ,

  1. First API call it returns JWT token[jwtToken]

def consumeAuthToken(authCode: String)(implicit req: Request, w: Wiring): Future[Response] = {
for {
withCode <- Try(json"""{ "code": ${authCode}}""").toFuture
r <- w.postgrest ? (method = Post, path = "/rpc/consume_auth_codes", json = Option(withCode))
json <- r.jsonArrHeadF
resp <- json.consume_auth_codes match {
case json""" { "found": false }""" =>
CANNED(NotFound, s"${authCode} is not a valid code", false)
case json""" { "found": true, "used": true }""" =>
CANNED(NotFound, s"${authCode} is not a valid code", false)
case json""" { "found": true, "used": false, "result": { "email": $email , "principal_id": $principal_id } }""" =>
val token = createJWT(email.as[String], principal_id.as[String]).get
CANNED(Ok, json"""{ "jwtToken": $token }""")
case any =>
CANNED(InternalServerError, any)
}
} yield resp
}
Response : jwtToken : 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkc3QiOiJjb252ZW5lLXFhIiwiZXhwIjoxNTU5OTAyMTU3LCJpYXQiOjE1NTcyMjM3NTcsImlzcyI6ImNvbnZlbmUtcWEiLCJzdWJfZW1haWwiOiJjb252ZW50ZXN0MDk5QGdtYWlsLmNvbSIsInN1YiI6IjMzYTJlZTNkLWQwMGItNGY4YS1hN2NlLTEwYzI0ZTdiNWJjMiIsInN1Yl9uYW1lIjoiIiwic3ViX2dyYXZhdGFyIjoiIiwic3ViX3Byb3ZpZGVyLW5hbWUiOiJjb252ZW5lLWVtYWlsIiwic3ViX3Byb3ZpZGVyLWlkIjoiY29udmVudGVzdDA5OUBnbWFpbC5jb20ifQ.XAEWEhNL92yYjClNsOgjb1tjIgxyBzhwubhaM5iVrwU'

  1. Second call goes to : -

def ensureUserExists(manager:Boolean)(implicit req: Request, w:Wiring): Future[Response] = {
for {
i <- req.parseJWT.toFuture
pr = i.sub_provider-name.map(_.toString).getOrElse("")
resJF <- checkSignOut()
respS=resJF.getContentString()
_ <- if(pr.equals("convene-email") || manager ) if(respS.size>2 && respS.substring(9,13).equals("true")) Future.Done else Future.exception(HTTPError(BadRequest, " new Invalid request body"))
else Future.Done
i <- req.parseJWT.toFuture
pr_provider = i.sub_provider-name.map(pp => json"""{"pr_provider-name": $pp}""").getOrElse(json"{}")
response <- w.models ? (path = "/api/models/users", method = Post,
json = Some(
json"""{
"pr_id": ${i.sub},
"pr_name": ${i.sub_name},
"pr_email": ${i.sub_email},
"manager": $manager
}""" ++ pr_provider))
resp <- response.jsonF
_ <- if (!manager) checkForPendingInvitations(i.sub) else Future.Done
responseCookies <- if (manager) checkManagerInvitation(i) else Future.value(Seq.empty)
_ <- if (resp.created.as[Boolean]) sendWelcomeEmail(i, manager) else Future.Done
} yield mkResp(Ok, Json.format(resp), cookies = responseCookies)
}

///

def checkManagerInvitation(i: TokenInfo)(implicit req: Request, w: Wiring): Future[Seq[Cookie]] = {
req.cookies.get("convene-manager-login") match {
case None => Future.value(Seq.empty)
case Some(c) =>
println(debug"""Login cookie ${c.value}""")
val payload = Some(json"""{
"principalID": ${i.sub},
"principalEmail": ${i.sub_email},
"principalName": ${i.sub_name},
"principalGravatar": ${i.sub_gravatar},
"blob": ${c.value}
}""")
val resp = w.invitations ? (method = Post, path = "/api/invitations/members/redeem", json = payload, propagateFailedResponse = true)
c.maxAge = 0.seconds
c.httpOnly=true // Is this right position way to enable
resp.map(_ => Seq(c))
}
}

How the jwt is been constructed as part of response .where have to add httpOnly true
@perrydbucs please have a look