Giter VIP home page Giter VIP logo

jwt-scala's Introduction

JWT Scala

Scala support for JSON Web Token (JWT). Supports Java 8+, Scala 2.12, Scala 2.13 and Scala 3 (for json libraries that support it). Dependency free. Optional helpers for Play Framework, Play JSON, Json4s Native, Json4s Jackson, Circe, uPickle and Argonaut.

Contributor's guide

Usage

Detailed documentation is on the Microsite.

JWT Scala is divided in several sub-projects each targeting a specific JSON library, check the doc from the menu of the Microsite for installation and usage instructions.

Algorithms

If you are using String key, please keep in mind that such keys need to be parsed. Rather than implementing a super complex parser, the one in JWT Scala is pretty simple and might not work for all use-cases (especially for ECDSA keys). In such case, consider using SecretKey or PrivateKey or PublicKey directly. It is way better for you. All API support all those types.

Check ECDSA samples for more infos.

Name Description
HMD5 HMAC using MD5 algorithm
HS224 HMAC using SHA-224 algorithm
HS256 HMAC using SHA-256 algorithm
HS384 HMAC using SHA-384 algorithm
HS512 HMAC using SHA-512 algorithm
RS256 RSASSA using SHA-256 algorithm
RS384 RSASSA using SHA-384 algorithm
RS512 RSASSA using SHA-512 algorithm
ES256 ECDSA using SHA-256 algorithm
ES384 ECDSA using SHA-384 algorithm
ES512 ECDSA using SHA-512 algorithm
EdDSA EdDSA signature algorithms

Security concerns

This lib doesn't want to impose anything, that's why, by default, a JWT claim is totally empty. That said, you should always add an issuedAt attribute to it, probably using claim.issuedNow. The reason is that even HTTPS isn't perfect and having always the same chunk of data transfered can be of a big help to crack it. Generating a slightly different token at each request is way better even if it adds a bit of payload to the response. If you are using a session timeout through the expiration attribute which is extended at each request, that's fine too. I can't find the article I read about that vulnerability but if someone has some resources about the topic, I would be glad to link them.

License

This software is licensed under the Apache 2 license, quoted below.

Copyright 2021 JWT-Scala Contributors.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

jwt-scala's People

Contributors

austinpernell avatar baccata avatar bestehle avatar bodand avatar brakthehack avatar crispywalrus avatar dacr avatar dwhitney avatar erwan avatar etspaceman avatar fahman avatar ggrossman avatar guymers avatar jan0sch avatar massimosiani avatar msinton avatar omainegra avatar pauldijou avatar perotom avatar prakhunov avatar sbrunk avatar scala-steward avatar sideeffffect avatar steven-barnes avatar timothyklim avatar tpolecat avatar vhiairrassary avatar vic avatar vpavkin avatar xuwei-k avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jwt-scala's Issues

Play request.jwtSession can't deserialize when using a non-empty claim

Hello,

Maybe I am missing something but I can't figure out how to use custom claim (expiration and issuedAt) with Play sub project.

I have no problem to deserialize simple Payload (secret: changeme, algorythm: HS256):
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJtZW1iZXIiOnsidXNlcklkIjoxLCJ1c2VyVXVpZCI6IkhlcmF1ZCBLYXJpbSJ9fQ.OU1-WxnNIE4CosHXds3jty0kJeRtfYeeJyahFkyTGSY gives me :
JwtSession({"typ":"JWT","alg":"HS256"},{"member":{"userId":1,"userUuid":"Heraud Karim"}},OU1-WxnNIE4CosHXds3jty0kJeRtfYeeJyahFkyTGSY) as expected

But if I add specific claim the deserialized bearer is empty :
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0OTI3OTQwMjksIm1lbWJlciI6eyJ1c2VySWQiOjEsInVzZXJVdWlkIjoiSGVyYXVkIEthcmltIn19.TzVQSaoFNw41TKvdamAWUfEV2KwHpmCRTrGw9LArP74gives me :
JwtSession({"typ":"JWT","alg":"HS256"},{},) instead of JwtSession({"typ":"JWT","alg":"HS256"},{"exp": 1492794029,"member":{"userId":1,"userUuid":"Heraud Karim"}},TzVQSaoFNw41TKvdamAWUfEV2KwHpmCRTrGw9LArP74)

I tried with 'exp' and 'iat' it fails to deserialize it. Tried with 0.12.1 and 0.11.0.

I am probably missing a step. Thanks for a hint

Karim

value jwtSession is not a member of play.api.mvc.Request

Hi there,

after installing play-jwt I randomly get errors like:

Error:(22, 13) value jwtSession is not a member of play.api.mvc.Request[A]
    request.jwtSession.getAs[User]("user") match {
            ^

and I've to manually reload sbt dependencies. This is my build.sbt file

name := "Project"
version := "0.0.1"
inConfig(Compile)(mappings in packageBin <++= Defaults.sourceMappings)
lazy val root = (project in file(".")).enablePlugins(PlayScala)

scalaVersion := "2.11.7"
libraryDependencies ++= {
  val postgresV              = "9.4.1207"
  val nscalaTimeV            = "2.6.0"
  val playSlickV             = "1.1.1"
  val slickPgV               = "0.10.2"
  val slickJodaMapperVersion = "2.1.0"

  Seq(
    cache,
    ws,
    specs2 % Test,
    "org.postgresql"              %  "postgresql"                           % postgresV,
    "com.github.tminglei"         %% "slick-pg"                             % slickPgV,
    "com.github.tminglei"         %% "slick-pg_play-json"                   % slickPgV,
    "com.typesafe.play"           %% "play-slick"                           % playSlickV,
    "com.typesafe.play"           %% "play-slick-evolutions"                % playSlickV,
    "com.github.nscala-time"      %% "nscala-time"                          % nscalaTimeV,
    "com.github.tototoshi"        %% "slick-joda-mapper"                    % slickJodaMapperVersion,
    "de.svenkubiak"               % "jBCrypt"                               % "0.4.1",
    "com.pauldijou"               %% "jwt-play"                             % "0.5.1",
    "com.amazonaws"               % "aws-java-sdk"                          % "1.10.64"
  )
}

resolvers += "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases"

// Play provides two styles of routers, one expects its actions to be injected, the
// other, legacy style, accesses its actions statically.
routesGenerator := InjectedRoutesGenerator

// Newrelic configuration
enablePlugins(NewRelic)
newrelicVersion := "3.27.0"
newrelicAppName := "Project"

// Enable filters (to use CORS filter
libraryDependencies += filters

Everything seems correct, I've not idea on what could cause that.

Release artifact to some public repo

I'd like to use play-json implementation of jwt, but don't want to build it myself.

Could you release an artifact somewhere, say, on sonatype repo?

invalid json

in JwtUtils.scala these lines create invalid json once the value (or its toString representation) contains quotation marks "

      case value: String => "\"" + value + "\""
      case value: Any => "\"" + value.toString + "\""
      case (key, value: String) => "\"" + key + "\":\"" + value + "\""
      case (key, value: Any) => "\"" + key + "\":\"" + value.toString + "\""

and the same applies to all

"\"" + key + "\":\""

Decode expired token

Hi, I have a question regarding decoding expired tokens. Is it possible to decode an expired token?

This is the token

Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIbWFjU0hBMjU2In0.eyJleHAiOjE0NTAyNzUyNzIsInVzZXIiOnsiaWRVc2VyIjo4Nzc3MywiaWRDb25jZXB0VXNlciI6NTgxMSwiZmlyc3ROYW1lIjoiRnJ1bnphIiwibGFzdE5hbWUiOiJMZWFmIiwiZW1haWwiOiJmcnVuemFAYXNzaXN0LnJvIn19.4um3Q2IuyXWMaohwUF5_fAiVdrIlen68Oqs2CLLLVlY

I can decode the token using http://jwt.io I am able to see the payload, without specifying any secret key.

{
  "exp": 1450275272,
  "user": {
    "idUser": 87773,
    "firstName": "Frunza",
    "lastName": "Leaf",
    "email": "[email protected]"
  }
}

Thanks,
Marius

Using jwt-scala as nested actions

This is one of my existing endpoint in my REST controller that is actually doing the registration of a new user:

def createUser = {
    Action.async(parse.tolerantJson) { request =>
      request.body.validate[User].fold(
        errors => Future.successful {
          BadRequest(Json.obj("status" -> "error", "message" -> JsError.toJson(errors)))
        },
        user => {
          dbService.createNewUser(user)
            .map(someUserId => {
              if (someUserId.isDefined) {
                // Send an EMail to the user
                supervisorActor ! EMailUser(user.email)
                Ok(Json.obj("status" -> "ok", "userId" -> someUserId.get), "email" -> user.email)
              }
              else
                UnprocessableEntity(Json.obj("status" -> "error", "message" -> s"user already exists for the given email ${user.email.toString}"))
            })
            .recover { case ex => InternalServerError(Json.obj("error" -> s"${ex.getMessage}")) }
        }
      )
    }
  }

I want to now make use of JWT and make this endpoint callable only if the user is an Admin. How can I nest this controller method with the Secured Action?

java.security.spec.InvalidKeySpecException: encoded key spec not recognized: Bad sequence size: 3

Hi,

I am trying to validate jwt token for azure ad. I have the public key as below:

val pubkey= "-----BEGIN CERTIFICATE-----\nMIIDBTCCAe2gAwIBAgIQZSAeaqWig4BHC1ksmNNcgjANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE3MDUwNjAwMDAwMFoXDTE5MDUwNzAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJL7dVZkeJ8JDTPIzFNMJo9oEkvDc52zrdqWSOmex0E/3rBe1tfRmUe2O9l6NYuc10QzPaNxnkyIwa5698suNUPxGlEOwvm/h5oPeFcuxAWcgYYv5s589HWFrNjCF8EfOjZ4vU5oE1744EzxdmBiaGbeE8HDBXn1vK4owlcjawgQNF7KQ6LjSWr7xtARDF2IoKE4RYy0V0uVN4eAQ3zWRWWUt3cpYjTl34EZ9pO6CE8/If7noj75g0RYd/AHkIMdXBC4SlnNz+boLbba2ksIB+5z9jVILjvZwqx7i+k2filqZkVmasB/o2ChUFbdwg6c8DTOlyS/qB25dcfoCN2GF+cCAwEAAaMhMB8wHQYDVR0OBBYEFGKpXQNrF5IoxS6bL4F92+gxOJlIMA0GCSqGSIb3DQEBCwUAA4IBAQA3HgW5SoHlvvQVxqqi+mtscDZLhNfe13iG/nx8Er5il82b79RVydNs+f9sYxc4T4ctnrZu7x5e7jInJedNdAlrPorBdw+SfvKJsmiNndXugMew1FlcQTQVIFDCbziaJav8rKyMxPfeKkc1aixbajWZkKg6OPmmJn2ceTocbn8PMQy20xNvcWUwgF5FZZIuPqu6feOLJcUIYw+0JFZ265xka30QXpmytcIxajIzpD4PRdCIBuVSqgXacAs4t4+w+OhnosD72yvXck8M4GwX1j+vcuyw0yhDGNMmqsHWP7H3jnJiGDrKhhdVyplzDhTfv2Whbv/dIDn+meLE3yyC5yGL\n-----END CERTIFICATE-----"
when I try to validate the token using Jwt.validate(token,pubkey, Seq(JwtAlgorithm.RS256))
I get the following stacktrace


java.security.spec.InvalidKeySpecException: encoded key spec not recognized: Bad sequence size: 3
  at org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi.engineGeneratePublic(Unknown Source)
  at org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi.engineGeneratePublic(Unknown Source)
  at java.security.KeyFactory.generatePublic(KeyFactory.java:328)
  at pdi.jwt.JwtUtils$.parsePublicKey(JwtUtils.scala:114)
  at pdi.jwt.JwtUtils$.verify(JwtUtils.scala:187)
  at pdi.jwt.JwtCore$$anonfun$validate$2.apply(Jwt.scala:654)
  at pdi.jwt.JwtCore$$anonfun$validate$2.apply(Jwt.scala:653)
  at pdi.jwt.JwtCore$class.validate(Jwt.scala:636)
  at pdi.jwt.Jwt$.validate(Jwt.scala:23)
  at pdi.jwt.JwtCore$class.validate(Jwt.scala:653)
  at pdi.jwt.Jwt$.validate(Jwt.scala:23)
  at pdi.jwt.JwtCore$class.validate(Jwt.scala:722)
  at pdi.jwt.Jwt$.validate(Jwt.scala:23)
  at pdi.jwt.JwtCore$class.validate(Jwt.scala:725)
  at pdi.jwt.Jwt$.validate(Jwt.scala:23)

Is there anything I am doing incorrectly?

Play 2.5.x support

Running example app play-angular-standalone with play-2.5.0 throws the Exception

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[RuntimeException: java.lang.NoSuchMethodError: play.api.libs.json.JsLookup$.$bslash$extension(Lplay/api/libs/json/JsLookupResult;Ljava/lang/String;)Lplay/api/libs/json/JsLookupResult;]]
    at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:269)
    at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:195)
    at play.api.GlobalSettings$class.onError(GlobalSettings.scala:160)
    at play.api.DefaultGlobal$.onError(GlobalSettings.scala:188)
    at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:98)
    at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:99)
    at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:98)
    at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:344)
    at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:343)
    at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
Caused by: java.lang.RuntimeException: java.lang.NoSuchMethodError: play.api.libs.json.JsLookup$.$bslash$extension(Lplay/api/libs/json/JsLookupResult;Ljava/lang/String;)Lplay/api/libs/json/JsLookupResult;
    at play.api.mvc.ActionBuilder$$anon$2.apply(Action.scala:463)
    at play.api.mvc.Action$$anonfun$apply$2$$anonfun$apply$5$$anonfun$apply$6.apply(Action.scala:112)
    at play.api.mvc.Action$$anonfun$apply$2$$anonfun$apply$5$$anonfun$apply$6.apply(Action.scala:112)
    at play.utils.Threads$.withContextClassLoader(Threads.scala:21)
    at play.api.mvc.Action$$anonfun$apply$2$$anonfun$apply$5.apply(Action.scala:111)
    at play.api.mvc.Action$$anonfun$apply$2$$anonfun$apply$5.apply(Action.scala:110)
    at scala.Option.map(Option.scala:146)
    at play.api.mvc.Action$$anonfun$apply$2.apply(Action.scala:110)
    at play.api.mvc.Action$$anonfun$apply$2.apply(Action.scala:103)
    at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:251)
Caused by: java.lang.NoSuchMethodError: play.api.libs.json.JsLookup$.$bslash$extension(Lplay/api/libs/json/JsLookupResult;Ljava/lang/String;)Lplay/api/libs/json/JsLookupResult;
    at pdi.jwt.JwtJson$.getAlgorithm(JwtJson.scala:19)
    at pdi.jwt.JwtJson$.getAlgorithm(JwtJson.scala:14)
    at pdi.jwt.JwtJsonCommon$class.encode(JwtJsonCommon.scala:24)
    at pdi.jwt.JwtJson$.encode(JwtJson.scala:14)
    at pdi.jwt.JwtSession.serialize(JwtSession.scala:61)
    at pdi.jwt.JwtPlayImplicits$RichResult.withJwtSession(JwtPlayImplicits.scala:61)
    at pdi.jwt.JwtPlayImplicits$RichResult.addingToJwtSession(JwtPlayImplicits.scala:82)
    at controllers.Application$$anonfun$login$1$$anonfun$apply$2.apply(Application.scala:30)
    at controllers.Application$$anonfun$login$1$$anonfun$apply$2.apply(Application.scala:28)
    at play.api.libs.json.JsResult$class.fold(JsResult.scala:72)

request.jwtSession should be an Option

Hi, I'm a user. Been having trouble since upgrading at some point (I can't identify exactly when the breakage occurred).

request.jwtSession returns a JwtSession all the time - when there is no value supplied there's a .getOrElse(JwtSession()).

This JwtSession call is impure as it depends on time (due to default claim).

Also for some reason the request.jwtSession.isEmpty does not return true for that default value, either. So the only way I can check for emptiness (ie no token) is to do request.jwtSession.signature == "" instead of request.jwtSession.isEmpty.

Hope this is clear.

json4s version for use with jwt-json4s-native

Hi,

It seems that if you include the newest version of json4s (3.3.0), this will cause problems with render() and the like. I couldn't see a version to use mentioned anywhere; but inspecting jwt-scala it seems you use 2.10 -> You may want to mention that somewhere =)

Why is validateTiming in seconds?

I think its natural to specify "exp" and "notBefore" fields as milliseconds since the epoch.

Is there a specific reason as to why seconds are being used?

example 2.12.x in play 2.6.x ?

import pdi.jwt.JwtSession._
...
val session = request.jwtSession.getAs[Obj]("name")

error:
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[RuntimeException: java.lang.NoClassDefFoundError: Could not initialize class pdi.jwt.JwtSession$]]
at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:255)
at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:182)
at play.core.server.AkkaHttpServer$$anonfun$$nestedInanonfun$executeHandler$1$1.applyOrElse(AkkaHttpServer.scala:251)
at play.core.server.AkkaHttpServer$$anonfun$$nestedInanonfun$executeHandler$1$1.applyOrElse(AkkaHttpServer.scala:250)
at scala.concurrent.Future.$anonfun$recoverWith$1(Future.scala:412)

Parsing function is (too much ?) strict

A set of REGEX is used to parse JWT token header attributes such as the algorithm:

private val extractAlgorithmRegex = "\"alg\":\"([a-zA-Z0-9]+)\"".r

In my case, the JWT token is produced by a python library that generates the following header:

{"alg": "RS256", "typ": "JWT"}

In such case, jwt-scala fails to parse our token due to spaces that are added in the string.
My question, is "should I force JWT libraries to produce tokens without spaces or should we 1) improve the regex or 2) use a json unmarshaler before checking the header ?

Update json4s to 3.5.0

Hi,

I am using json4s in my project along with jwt-scala. It worked ok with version 3.4.2 but today I updated to 3.5.0 and got this exeption:

java.lang.NoSuchMethodError: org.json4s.native.JsonMethods$.render(Lorg/json4s/JsonAST$JValue;Lorg/json4s/Formats;)Lscala/text/Document;

I reverted to 3.4.2 and have no rush to update to 3.5.0, but it would be nice to have the latest version. Specially since the current one referenced in jwt-scala is 3.3.0.

Why do we have different names for algorithms?

You are using names for algorithms like: [HmacMD5, HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384, HmacSHA512], and by default you are using HmacSHA256.

When I take a token generated by default to another server, written in a different language, it could not recognize the algorithm HmacSHA256. I then have to update the config to use HS256 or HS512.

I am wondering why you have extra names. They seems to be not official names.

WebSockets authentication

Hi,

I was just wondering how you would do to authenticate Websockets with Play 2.5 and jwt-play ?

Thanks,

Integration with satellizer

Hi Pauldijou,
This is a nice library, Im trying to integrate this using angularjs satellizer library and I'm having some issues . Actually satellizer is expecting a response object with a key "token", how do I implement this ?

Thanks.

Claim Does Not Include Data

Hi Paul,

I messaged you on Twitter the other day, and although I solved that particular issue, I've run into another. I'm attempting to send an Ok.addingToJwtSession, passing in the field "user", with a value user.id.toString (ie. Ok.addingToJwtSession("user", user.id.toString)). It sends a response with the token included. My client receives the token and stores it. Upon a request requiring authentication, the client sends the token in the header under the name "Authorization" with the prefix "Bearer " (ie. Authorization: Bearer ...). Play accepts the request, and attempts to authenticate the user by getting decoding the token, extracting the user's ID, and looking for the user. The code for this is:

def invokeBlock[A](request: Request[A], block: AuthenticatedRequest[A] => Future[Result]) = {
    request.jwtSession.getAs[Int]("user") match {
      case Some(id: Int) =>
        UserModel.get(id) match {
          case Some(user: User) =>
            block(new AuthenticatedRequest(user, request)).map(_.refreshJwtSession(request))
          case _ =>
            Future.successful(Unauthorized)
        }
      case _ =>
        Future.successful(Unauthorized)
}

When I walk through the debugging process, it appears that the claim for the token only contains an exp, and does not contain an entry for "user" as I would expect. I'm not sure what to do from here.

error in NBF determination?

Version:0.14.1

Testcode:

import pdi.jwt.Jwt
import pdi.jwt.JwtAlgorithm.RS512
import scala.io.Source


val publicKey = Source.fromFile("/Users/asheshambasta/code/centralapp/authengine/authengine/conf/rsa/public.pem").mkString // see below

Jwt.decodeAll(
  """eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJpc3MiOiJhdXRoZW5naW5lXzEuMC4wLXJUUjlqIiwic3ViIjoiZGlzdHJpYnV0b3ItY2VudHJhbGFwcF91c2VyLTE5NF9QLlJFQUQiLCJleHAiOjE1MTI4MzczMDc0NDIsIm5iZiI6MTUxMjc1MDkwNzQ0MiwiaWF0IjoxNTEyNzUwOTA3NDQyLCJhIjoidXNlci0xOTQiLCJyIjoiZGlzdHJpYnV0b3ItY2VudHJhbGFwcCIsImciOiJQLlJFQUQiLCJlcXZfZyI6IkQuQUREX1JFTU9WRV9DSEFJTlNfUExBQ0VTIn0.mLtCNwBGnfIlg74lc9IXpsKcOYsjls9QSgF4SLx5oUXmrp2zwAoAWgfkUiz8sYKYrj0Rz4iqh6Gw8uUpRyjUvLrysz6tWHncujgQTxbq20d_txJw_pZIAoc53Ma2J-epfHLLHJIDTA6vZVwLRH_uYuQCi9AGXzM-85qPlc-tz3442ed3tJgDOXpZ87vwHnndDRC6oma60cigkHDmwBcmSNtKtiMUOazCrCdNE1QeGrrINw2WfJekC7Aw4jJdhF7MEeJ7YBEOiMAAJ7tXsWy3BYiQiPtvbA3xQb_xXNX_d30qT0z6NRjUPKnxTpi93NbdfLifDPVJoJ9NKOTzYtzZNw""",
  publicKey,
  algorithms = RS512 :: Nil)

For testing, the publicKey (not used anywhere else) used is:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8uuI4AoRs4wbAVTHLupS
TFLV6GqTw3tqlxIFJmBqT9rszSAj0gsUCL1ryW1AWT7xhkVoutRSBqnzXzsa/aZg
rT3ttDx52ALQ6VipOxP321mnPMtwHv6HSGG8Z49Xr0i2Xsy64V2e4NrOnj/wRzmE
mharQUDZeQWTajhuYkxHjTmkzYc041M88VoZBlwQTrMqR+GiOAocMlxAWeNYaBro
cOeC42F1Ga+HmfDZLqKQ2HlpqKIOIxtADqFKpq7TC2z83Gkq6Cf10JcI4SjNMDCx
jW84rM/3IWW8Lim1RyRzHTih9a+WAYAuiTIuDvAgw33T6WVyFHvvUUi3ZAk3faeY
ZwIDAQAB
-----END PUBLIC KEY-----

decoded payload:

{
  "iss": "authengine_1.0.0-rTR9j",
  "sub": "distributor-centralapp_user-194_P.READ",
  "exp": 1512837307442,
  "nbf": 1512750907442,
  "iat": 1512750907442,
  "a": "user-194",
  "r": "distributor-centralapp",
  "g": "P.READ",
  "eqv_g": "D.ADD_REMOVE_CHAINS_PLACES"
}

I have the token issuer issuing the tokens with nbf set to the time of issue and the expiry time set to a reasonable delta above the current time.

Now the result for the decode statement above is a failure with JWtNotBeforeException:

res0: scala.util.Try[(String, String, String)] = Failure(pdi.jwt.exceptions.JwtNotBeforeException: The token will only be valid after +49907-03-04T01:24:02Z)

This happens when trying on a Scratch sheet in IntelliJ.

Could this be a bug? I understand the token is currently expired but the same happens for tokens issued very recently.

To me this looks like an issue with how the current time is computed and then compared to the nbf in the token; or am I missing something obvious?

NoSuchMethodError when creating JWT cookie with Gatling

When I try to create a cookie, part of a simulation, I get a NoSuchMethodError.

My code looks like this:

def getJWTCookie: String = {
    Jwt.encode("""{"user":1}""", "secretKey", JwtAlgorithm.HS256)
  }

I compile the code with the Zinc compiler of Gatling. I also tried to compile the code with the scala-maven-plugin. It also gave the same result.

The stacktrace:

java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at io.gatling.mojo.MainWithArgsInFile.runMain(MainWithArgsInFile.java:50)
        at io.gatling.mojo.MainWithArgsInFile.main(MainWithArgsInFile.java:33)
Caused by: java.lang.NoSuchMethodError: scala.Product.$init$(Lscala/Product;)V
        at pdi.jwt.JwtAlgorithm$HS256$.<init>(JwtAlgorithm.scala:65)
        at pdi.jwt.JwtAlgorithm$HS256$.<clinit>(JwtAlgorithm.scala)
        at nl.translink.util.CookieUtil.getJWTCookie(CookieUtil.scala:7)
        at nl.translink.simulations.FEAPIGatewaySimulation.<init>(FEAPIGatewaySimulation.scala:11)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
        at java.lang.Class.newInstance(Class.java:442)
        at io.gatling.app.Runner.run0(Runner.scala:79)
        at io.gatling.app.Runner.run(Runner.scala:64)
        at io.gatling.app.Gatling$.start(Gatling.scala:56)
        at io.gatling.app.Gatling$.fromArgs(Gatling.scala:41)
        at io.gatling.app.Gatling$.main(Gatling.scala:33)
        at io.gatling.app.Gatling.main(Gatling.scala)
        ... 6 more

Can you look at it please?

Thanks, Mike

Verify secret fail in online test https://jwt.io/

Hi, first of all thanks for sharing.

I'm trying to testing your library but the signature verification fails with the online tool in https://jwt.io/.
I tried with the clear-key and with base64-key but everytime the result is negative.
Can you check this?

Thanks, Simone

Multiple pdi.jwt objects clash in IntelliJ

Hi,

I can't get the play-angular-standalone to work with IntelliJ without tricks, there's an issue importing pdi.jwt._ since there's one of those package objects in each project. Would it make more sense to have different packages in each module?

Drop Play legacy support

Play Framework 2.4+ does only support Java 8+, so there isn't any reason for now to support play legacy for now.

jwt-json4s-native and jwt-json4s-jackson are missing at maven

Hi. Thank you for the nice libraries.

I set up build.sbt like the following according to the readme, but the library was not found.

libraryDependencies ++= Seq(
  "com.pauldijou" %% "jwt-json4s-jackson" % "0.4.0"
)

It seems that jwt-json4s-native and jwt-json4s-jackson are not published to maven central. search result

Is it possible to publish these libraries? or is there any other solution?

maxAge is in second

This is a block of code with comment from Play template

play.http {
    session {
        # Sets the max-age field of the cookie to 5 minutes.
        # maxAge = 300
    }
}

So the unit of maxAge is in seconds. However, in your code jwt-scala/play/src/main/scala/JwtSession.scala where you get the max age, you assume that maxAge is in milliseconds, and divide it by 1000.

val MAX_AGE: Option[Long] = getConfigMillis("play.http.session.maxAge").map(_ / 1000)

Is there any reason you treat maxAge as milliseconds, because it is standard that maxAge is specified in seconds. This will also affect other part of the Play application where normal session is involved, because the time for those session has been increased by 1000 times.

Exception in thread "main" java.lang.AbstractMethodError: pdi.jwt.JwtBase64$.pdi$jwt$JwtBase64Impl$$encoder()Ljava/util/Base64$Encoder;

  def generateToken(clientId: String): String = {

    val token = Jwt.encode("""{"user":1}""", "secretKey", JwtAlgorithm.HS256)
    token
    ""
  }
/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=57008:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/tools.jar:/Users/wangyoux/dev/Microservice/message-service/target/scala-2.11/classes:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/thoughtworks/paranamer/paranamer/2.8/paranamer-2.8.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-parser-combinators_2.11/1.0.5/scala-parser-combinators_2.11-1.0.5.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-java8-compat_2.11/0.8.0/scala-java8-compat_2.11-0.8.0.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/javax.inject/javax.inject/1/jars/javax.inject.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/play/shaded-oauth/1.0.4/shaded-oauth-1.0.4.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/play/shaded-asynchttpclient/1.0.4/shaded-asynchttpclient-1.0.4.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/play/play-ws-standalone_2.11/1.0.4/play-ws-standalone_2.11-1.0.4.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/play/play-ahc-ws-standalone_2.11/1.0.4/play-ahc-ws-standalone_2.11-1.0.4.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/play/cachecontrol_2.11/1.1.2/cachecontrol_2.11-1.1.2.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/ssl-config-core_2.11/0.2.2/ssl-config-core_2.11-0.2.2.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/module/jackson-module-scala_2.10/2.7.2/jackson-module-scala_2.10-2.7.2.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/module/jackson-module-paranamer/2.7.2/jackson-module-paranamer-2.7.2.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/pcollections/pcollections/2.1.2/pcollections-2.1.2.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/joda-time/joda-time/2.9.9/joda-time-2.9.9.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/nulab-inc/scala-oauth2-core_2.11/1.3.0/scala-oauth2-core_2.11-1.3.0.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/com.google.guava/guava/19.0/bundles/guava.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/com.google.code.findbugs/jsr305/1.3.9/jars/jsr305.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/github/cb372/scalacache-guava_2.11/0.9.4/scalacache-guava_2.11-0.9.4.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/github/cb372/scalacache-core_2.11/0.9.4/scalacache-core_2.11-0.9.4.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/io/igl/jwt_2.11/1.2.0/jwt_2.11-1.2.0.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/commons-codec/commons-codec/1.10/jars/commons-codec.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-stream_2.11/2.5.3/akka-stream_2.11-2.5.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-slf4j_2.11/2.5.3/akka-slf4j_2.11-2.5.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-remote_2.11/2.5.3/akka-remote_2.11-2.5.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-protobuf_2.11/2.5.3/akka-protobuf_2.11-2.5.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-persistence_2.11/2.5.3/akka-persistence_2.11-2.5.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-distributed-data_2.11/2.5.3/akka-distributed-data_2.11-2.5.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-contrib_2.11/2.5.3/akka-contrib_2.11-2.5.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-cluster_2.11/2.5.3/akka-cluster_2.11-2.5.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-cluster-tools_2.11/2.5.3/akka-cluster-tools_2.11-2.5.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-cluster-sharding_2.11/2.5.3/akka-cluster-sharding_2.11-2.5.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-agent_2.11/2.5.3/akka-agent_2.11-2.5.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-actor_2.11/2.5.3/akka-actor_2.11-2.5.3.jar:/Users/wangyoux/.ivy2/local/org.parasol.service/http-service_2.11/1.0/jars/http-service_2.11.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/io/protostuff/protostuff-runtime-registry/1.5.5/protostuff-runtime-registry-1.5.5.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/io/protostuff/protostuff-runtime/1.5.5/protostuff-runtime-1.5.5.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/io/protostuff/protostuff-json/1.5.5/protostuff-json-1.5.5.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/io/protostuff/protostuff-core/1.5.5/protostuff-core-1.5.5.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/io/protostuff/protostuff-collectionschema/1.5.5/protostuff-collectionschema-1.5.5.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/io/protostuff/protostuff-api/1.5.5/protostuff-api-1.5.5.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/github/jnr/jffi/1.2.14/jffi-1.2.14.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/github/jnr/jffi/1.2.14/jffi-1.2.14-native.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/github/jnr/jnr-constants/0.9.6/jnr-constants-0.9.6.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/github/jnr/jnr-ffi/2.1.2/jnr-ffi-2.1.2.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/github/jnr/jnr-x86asm/1.0.2/jnr-x86asm-1.0.2.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/github/scopt/scopt_2.11/3.4.0/scopt_2.11-3.4.0.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/config/1.3.1/config-1.3.1.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-http-core_2.11/10.0.7/akka-http-core_2.11-10.0.7.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-http-spray-json_2.11/10.0.0/akka-http-spray-json_2.11-10.0.0.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-http_2.11/10.0.7/akka-http_2.11-10.0.7.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/akka/akka-parsing_2.11/10.0.7/akka-parsing_2.11-10.0.7.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/commons-logging/commons-logging/1.2/jars/commons-logging.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/io/aeron/aeron-client/1.2.5/aeron-client-1.2.5.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/io/aeron/aeron-driver/1.2.5/aeron-driver-1.2.5.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/io/netty/netty/3.10.6.Final/netty-3.10.6.Final.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/io/spray/spray-json_2.11/1.3.2/spray-json_2.11-1.3.2.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/me/maciejb/etcd-client/etcd-client_2.11/0.2.0/etcd-client_2.11-0.2.0.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/agrona/Agrona/0.9.5/agrona-0.9.5.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/org.apache.httpcomponents/httpclient/4.5.2/jars/httpclient.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/org.apache.httpcomponents/httpcore/4.4.4/jars/httpcore.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/org.joda/joda-convert/1.8.1/jars/joda-convert.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/lmdbjava/lmdbjava/0.0.5/lmdbjava-0.0.5.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/ow2/asm/asm/5.0.3/asm-5.0.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/ow2/asm/asm-analysis/5.0.3/asm-analysis-5.0.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/ow2/asm/asm-commons/5.0.3/asm-commons-5.0.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/ow2/asm/asm-tree/5.0.3/asm-tree-5.0.3.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/ow2/asm/asm-util/5.0.3/asm-util-5.0.3.jar:/Users/wangyoux/.ivy2/local/org.parasol.service/service-common-core_2.11/1.0/jars/service-common-core_2.11.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/org.reactivestreams/reactive-streams/1.0.0/jars/reactive-streams.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/org.scala-lang/scala-library/2.11.8/jars/scala-library.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/org.scala-lang/scala-reflect/2.11.8/jars/scala-reflect.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/scala-stm/scala-stm_2.11/0.8/scala-stm_2.11-0.8.jar:/Users/wangyoux/.ivy2/local/org.parasol.service/service-data-provider_2.11/1.0/jars/service-data-provider_2.11.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/codehaus/jackson/jackson-core-asl/1.9.9/jackson-core-asl-1.9.9.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/codehaus/jackson/jackson-mapper-asl/1.9.9/jackson-mapper-asl-1.9.9.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/keycloak/keycloak-adapter-core/1.6.1.Final/keycloak-adapter-core-1.6.1.Final.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/keycloak/keycloak-common/1.6.1.Final/keycloak-common-1.6.1.Final.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/keycloak/keycloak-core/1.6.1.Final/keycloak-core-1.6.1.Final.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/pauldijou/jwt-core-impl_2.11/0.14.0/jwt-core-impl_2.11-0.14.0.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/pauldijou/jwt-core-legacy-impl_2.11/0.14.0/jwt-core-legacy-impl_2.11-0.14.0.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/pauldijou/jwt-core-legacy_2.11/0.14.0/jwt-core-legacy_2.11-0.14.0.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/pauldijou/jwt-core_2.11/0.14.0/jwt-core_2.11-0.14.0.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/pauldijou/jwt-json-common-legacy_2.11/0.14.0/jwt-json-common-legacy_2.11-0.14.0.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/pauldijou/jwt-play-json-legacy_2.11/0.14.0/jwt-play-json-legacy_2.11-0.14.0.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/pauldijou/jwt-play_2.11/0.14.0/jwt-play_2.11-0.14.0.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/bouncycastle/bcpkix-jdk15on/1.57/bcpkix-jdk15on-1.57.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk15on/1.57/bcprov-jdk15on-1.57.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/ch.qos.logback/logback-classic/1.1.7/jars/logback-classic.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/ch.qos.logback/logback-core/1.1.7/jars/logback-core.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.7.2/jackson-annotations-2.7.2.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.7.2/jackson-core-2.7.2.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.7.2/jackson-databind-2.7.2.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/com.fasterxml.jackson.datatype/jackson-datatype-jdk8/2.7.1/bundles/jackson-datatype-jdk8.jar:/Users/wangyoux/dev/activator-dist-1.3.12/repository/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/2.7.1/bundles/jackson-datatype-jsr310.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/play/play-datacommons_2.11/2.5.4/play-datacommons_2.11-2.5.4.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/play/play-functional_2.11/2.5.4/play-functional_2.11-2.5.4.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/play/play-iteratees_2.11/2.5.4/play-iteratees_2.11-2.5.4.jar:/Users/wangyoux/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/play/play-json_2.11/2.5.4/play-json_2.11-2.5.4.jar parasol.gateway.router.http.sso.oauth2.token.TokenProvider
objc[4061]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/bin/java and /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/libinstrument.dylib. One of the two will be used. Which one is undefined.
Exception in thread "main" java.lang.AbstractMethodError: pdi.jwt.JwtBase64$.pdi$jwt$JwtBase64Impl$$encoder()Ljava/util/Base64$Encoder;
	at pdi.jwt.JwtBase64Impl$class.encodeString(JwtBase64Impl.scala:15)
	at pdi.jwt.JwtBase64$.encodeString(JwtBase64.scala:3)
	at pdi.jwt.JwtBase64$.encodeString(JwtBase64.scala:13)
	at pdi.jwt.JwtCore$class.encode(Jwt.scala:79)
	at pdi.jwt.Jwt$.encode(Jwt.scala:23)
	at pdi.jwt.JwtCore$class.encode(Jwt.scala:109)
	at pdi.jwt.Jwt$.encode(Jwt.scala:23)
	at parasol.gateway.router.http.sso.oauth2.token.AccessTokenGenerator$class.generateToken(AccessTokenGenerator.scala:81)
	at parasol.gateway.router.http.sso.oauth2.token.AccessTokenGenerator$.generateToken(AccessTokenGenerator.scala:91)
	at parasol.gateway.router.http.sso.oauth2.token.TokenProvider$.delayedEndpoint$parasol$gateway$router$http$sso$oauth2$token$TokenProvider$1(AccessTokenGenerator.scala:95)
	at parasol.gateway.router.http.sso.oauth2.token.TokenProvider$delayedInit$body.apply(AccessTokenGenerator.scala:93)
	at scala.Function0$class.apply$mcV$sp(Function0.scala:34)
	at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
	at scala.App$$anonfun$main$1.apply(App.scala:76)
	at scala.App$$anonfun$main$1.apply(App.scala:76)
	at scala.collection.immutable.List.foreach(List.scala:381)
	at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35)
	at scala.App$class.main(App.scala:76)
	at parasol.gateway.router.http.sso.oauth2.token.TokenProvider$.main(AccessTokenGenerator.scala:93)
	at parasol.gateway.router.http.sso.oauth2.token.TokenProvider.main(AccessTokenGenerator.scala)

Code samples on gh-pages are unreadable (rendered without line breaks)

Hi there, thanks for your great library! This is not an actual issue with your source, just something I wanted to point out is a little bit frustrating with the documentation.

On your Samples pages, (e.g. http://pauldijou.fr/jwt-scala/samples/jwt-core/) the code snippets are strangely rendered with no line breaks, appearing on the page as a single very-long line that I have to scroll horizontally to read. I had to copy-paste and transform these samples in order to read and use them. I'm guessing this was not intentional, maybe some regression when changing how the pages were rendered at some point? Just a little something that you might want to look into :)

Ability to add own claim?

Hello,
Is it possible to add my own custom claim to JwtClaim in type safe manner?
For example i want to create claim as (added my_custom_claim property):
{ "iss": "issuer", "sub": "user", "aud": ["service-"], "exp": 1506094471, "iat": 1506093871, "jti": "d82e9ff9-c996-4654-8ba0-8926d8721af6", "my_custom_claim" : "my custom claim value" }

Controlling what JCE security provider is used for signing

Ideally it will be possible to specify to the library what security provider it should use or provide some sort of mediation layer that will do decide how to perform signing/validation. That way the library would be agnostic to the underlying security implementation.

Thanks

JCE cannot authenticate the provider BC

Exception in thread "main" java.security.NoSuchProviderException: JCE cannot authenticate the provider BC
at javax.crypto.JceSecurity.getInstance(JceSecurity.java:101)
at javax.crypto.Mac.getInstance(Mac.java:222)
at pdi.jwt.JwtUtils$.sign(JwtUtils.scala:121)
at pdi.jwt.JwtUtils$.sign(JwtUtils.scala:150)
at pdi.jwt.JwtUtils$.sign(JwtUtils.scala:159)
at pdi.jwt.JwtCore$class.encode(Jwt.scala:80)
at pdi.jwt.Jwt$.encode(Jwt.scala:23)
at pdi.jwt.JwtCore$class.encode(Jwt.scala:109)
at pdi.jwt.Jwt$.encode(Jwt.scala:23)
at pdi.jwt.JwtCore$class.encode(Jwt.scala:149)
at pdi.jwt.Jwt$.encode(Jwt.scala:23)

i use SBT assembly
i learn scala recently, i don't know how to fix the bug, maybe you can give me some advise.
Thanks.

[jwt-play] Having two header name configuration

(Feature request)

With Play 2.6 and default back-end (akka-http), the Authorization header is currently not rendered in response. IMHO, this is a bug (Authorization header should be a custom header in response).

play.http.session.jwtName should be separated in two different configuration :

  • one for request header play.http.session.jwt.requestName with current default: Authorization
  • one for response header play.http.session.jwt.responseName with another default: Set-Authorization (As for the pair Cookie / Set-Cookie)

This feature request follow the discussion in playframework/playframework#7549

If this feature is agreed, I can submit a PR.

Play JwtSession is incompatible with akka-http

I recently switched a application form Play 2.5 to the Play 2.6 Milestone and noticed that the Session broke in the process.

After some digging I found that akka-http declares the Authorization header as a request header, which means it is filtered out in responses. So the client does not receive the JWT Token and cannot send the updated Authorization header.

I switched from the Authorization header to a custom JWT-Auth header, but now the client has to send it's JWT Token also in the custom header. Maybe the JwtSession.HEADER_NAME should be replaced by JwtSession.REQUEST_HEADER_NAME and JwtSession.RESPONSE_HEADER_NAME, so you can use a custom header in the responses.

Add a license

Hi @pauldijou, great work! Could you please specify under what license is this code released? I want to use it in a commercial project and do some customizations, but I'm not sure if I can.

Support play 2.4

Play-json API has changed in 2.4. It would be great to have jwt-scala support for it.

JwtJsonCommon in jar

Would be nice to have just JwtJsonCommon exported in a jar instead of having to pick a json lib (and having the json lib version blocked ...)

jwt-json-common ?

Allow decoders to accept a Base64 URL encoded String parameter

It would be a very nice convenience to be able to pass in a Base64 URLEncoded String as a parameter to the decode() methods--as this is what is often used for secrets with authentication services.

The workaround for now is to manually decode the secret and then construct a new SecretKey with the byte array and the algorithm. Unfortuntely, it's a bit redundant to have to go that way since we specify the algorithm(s) in the decoder anyway.

For example, instead of this:

val decodedSecretByteArray = Base64.getUrlDecoder.decode(base64Secret)
Jwt.decode(token, new SecretKeySpec(decodedSecretByteArray, "HmacSHA256"), JwtAlgorithm.allHmac())

We could just do this:

Jwt.decode(token, base64Secret, JwtAlgorithm.allHmac())

Would you consider adding this capability? Or am I missing something that would make this easier?

make JwtJson4s.parseClaim, JwtJson4s.parseHeader publicly accessible

Hi,

I am not able to use JwtJson4s.decode() without first getting the publicKey (since my signature is always non-empty). But in order to get the publicKey, my specific approach to using JWT involves looking up the publicKey from a database using the so-called kid header claim.

So, the process is:

  1. decode the claims
  2. check if the claims are expired (if not continue)
  3. decode the header
  4. get the kid from the decoded header
  5. select the corresponding publicKey from the database based on the kid
  6. using the publicKey, validate

This means I ended up copying and pasting the parse boilerplate of these protected methods, that way I didn't need any key to decode the claims:

val parts = token.split("\\.")
val claims = JwtJson4s.readClaim(parse(JwtBase64.decodeString(parts(1))))
val keyId = extractString(parse(JwtBase64.decodeString(parts(0))), "kid").get

Would it be alright to make those methods publicly accessible for this fairly common use case? Or, could there be a decodeAll method that did not perform validate?

Here is the boilerplate used above that it would help to avoid:

protected def parse(value: String): JObject = jparse(value) match {
    case res: JObject => res
    case _ => throw new RuntimeException(s"Couldn't parse [$value] to a JObject")
  }

  private def extractString(json: JObject, fieldName: String): Option[String] = (json \ fieldName) match {
    case JString(value) => Option(value)
    case JNull => None
    case JNothing => None
    case _ => throw new JwtNonStringException(fieldName)
  }

Typo in a file

In the legacy version of JwtBase64Impl.scala, you have this:

def decode(value: Array[Byte]): Array[Byte] = codec.encode(value)

=> should be replaced by:

def decode(value: Array[Byte]): Array[Byte] = codec.decode(value)

Furthermore, standard use of JWT mentions an AuthorizationHeader with a Bearer String:
"Authorization Bearer myToken".

So this lines would lead to an error when decoding step takes place:

Play.maybeApplication.flatMap(_.configuration.getString("session.jwtName")).getOrElse("Authorization")

What I made actually is to alter this line as follows in order to ONLY get the token:

request.headers.get(JwtSession.HEADER_NAME).flatMap(_.split(" ").drop(1).headOption).map(JwtSession.deserialize).getOrElse(JwtSession())

in order to retrieve the key without the Bearer string, that would break the "decode" step.

Otherwise I use the whole with Play 2.3.7 and it works great ! Thanks for the job :)

May you create an SBT entry in order to integrate it easily in any app?

Michael

Scala 2.12 support

Hi Paul,
thanks for great library! Can you please also add support and release for Scala 2.12?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.