$30 off During Our Annual Pro Sale. View Details »

JWT - To authentication & beyond! (v2)

JWT - To authentication & beyond! (v2)

Tokens are widely used to identify resources and try to add some security to insecure environments, but sometimes the management of those identifiers can get a bit complex - even more on distributed systems. What if we could have an intelligent token, one that simplifies the way things works without losing integrity or security?
In this talk we present JSON Web Tokens as an alternative for smart and self contained tokens, explaining how to use each claim and giving some common use cases.

Luís Cobucci

July 05, 2018
Tweet

More Decks by Luís Cobucci

Other Decks in Technology

Transcript

  1. JWT
    To infinity

    & beyond!
    authentication
    Luís Cobucci

    @lcobucci
    https://goo.gl/gbd3H5

    View Slide

  2. Tokens?
    https://goo.gl/C0LI6F

    View Slide

  3. Browser
    Server DB

    View Slide

  4. Browser
    Server
    1. presents credentials
    POST /login

    {

    "email": "[email protected]",
    "password": "amazing!"

    }
    DB

    View Slide

  5. Browser
    Server DB
    1. presents credentials
    2. validates and starts a session

    View Slide

  6. Browser
    Server DB
    1. presents credentials
    2. validates and starts a session
    200 OK
    Set-Cookie: PHPSESSIONID=ABC123;
    Domain=foo.bar; Secure; HttpOnly;
    Expires=Thu, 1 Jun 2017 12:00:00
    GMT

    View Slide

  7. Browser
    Server DB
    1. presents credentials
    2. validates and starts a session
    200 OK
    Set-Cookie: PHPSESSIONID=ABC123;
    Domain=foo.bar; Secure; HttpOnly;
    Expires=Thu, 1 Jun 2017 12:00:00
    GMT

    View Slide

  8. Browser
    Server DB
    1. presents credentials
    2. validates and starts a session
    3. sends cookies on next requests
    GET /
    Cookie: PHPSESSIONID=ABC123

    View Slide

  9. Browser
    Server DB
    1. presents credentials
    2. validates and starts a session
    3. sends cookies on next requests
    4. reads session data and returns a
    specific response for logged user
    200 OK
    Hello John!

    View Slide

  10. “ (…) Each request from any client
    contains all the information
    necessary to service the request, and
    session state is held in the client.
    Representational State Transfer - Wikipedia

    View Slide

  11. A mission
    http://goo.gl/RfVHNu

    View Slide

  12. {
    "token": "abc123", "uid": 1, "expiration": "…",

    "scope": ["a", "b", "c"]
    }

    View Slide

  13. {
    "token": "abc123", "uid": 1,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "def123", "uid": 2,

    "expiration": "…", "scope": ["a", "b"]
    }

    View Slide

  14. {
    "token": "abc123", "uid": 1,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "def123", "uid": 2,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "abc456", "uid": 3,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "def456", "uid": 4,

    "expiration": "…", "scope": ["a", "b"]
    }

    View Slide

  15. {
    "token": "abc123", "uid": 1,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "def123", "uid": 2,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "abc456", "uid": 3,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "def456", "uid": 4,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "abc789", "uid": 5,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "def789", "uid": 6,

    "expiration": "…", "scope": ["a"]
    }
    {
    "token": "ghi123", "uid": 1,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "jkl123", "uid": 2,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "ghi456", "uid": 3,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "jkl456", "uid": 4,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "ghi789", "uid": 5,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "jkl789", "uid": 6,

    "expiration": "…", "scope": ["a"]
    }

    View Slide

  16. {
    "token": "abc123", "uid": 1,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "def123", "uid": 2,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "abc456", "uid": 3,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "def456", "uid": 4,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "abc789", "uid": 5,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "def789", "uid": 6,

    "expiration": "…", "scope": ["a"]
    }
    {
    "token": "ghi123", "uid": 1,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "jkl123", "uid": 2,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "ghi456", "uid": 3,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "jkl456", "uid": 4,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "ghi789", "uid": 5,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "jkl789", "uid": 6,

    "expiration": "…", "scope": ["a"]
    }
    {
    "token": "abc123", "uid": 1,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "def123", "uid": 2,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "abc456", "uid": 3,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "def456", "uid": 4,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "abc789", "uid": 5,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "def789", "uid": 6,

    "expiration": "…", "scope": ["a"]
    }
    {
    "token": "ghi123", "uid": 1,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "jkl123", "uid": 2,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "ghi456", "uid": 3,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "jkl456", "uid": 4,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "ghi789", "uid": 5,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "jkl789", "uid": 6,

    "expiration": "…", "scope": ["a"]
    }
    {
    "token": "abc123", "uid": 1,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "def123", "uid": 2,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "abc456", "uid": 3,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "def456", "uid": 4,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "abc789", "uid": 5,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "def789", "uid": 6,

    "expiration": "…", "scope": ["a"]
    }
    {
    "token": "ghi123", "uid": 1,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "jkl123", "uid": 2,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "ghi456", "uid": 3,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "jkl456", "uid": 4,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "ghi789", "uid": 5,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "jkl789", "uid": 6,

    "expiration": "…", "scope": ["a"]
    }
    {
    "token": "abc123", "uid": 1,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "def123", "uid": 2,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "abc456", "uid": 3,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "def456", "uid": 4,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "abc789", "uid": 5,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "def789", "uid": 6,

    "expiration": "…", "scope": ["a"]
    }
    {
    "token": "ghi123", "uid": 1,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "jkl123", "uid": 2,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "ghi456", "uid": 3,

    "expiration": "…", "scope": ["a", "b", "c"]
    }
    {
    "token": "jkl456", "uid": 4,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "ghi789", "uid": 5,

    "expiration": "…", "scope": ["a", "b"]
    }
    {
    "token": "jkl789", "uid": 6,

    "expiration": "…", "scope": ["a"]
    }

    View Slide

  17. Wonderful, right?
    http://goo.gl/9jQFkj

    View Slide

  18. No!
    http://goo.gl/XHI1fw

    View Slide

  19. We need

    SIMPLE
    !
    it

    View Slide

  20. Luís Cobucci

    @lcobucci
    https://jobs.usabilla.com

    View Slide

  21. JOSE
    JSON Object Signing and Encryption

    View Slide

  22. JOSE
    JSON Object Signing and Encryption
    jws jwa
    jwt jwe
    jwk

    View Slide

  23. eyJ0eXAiOiJKV1QiLCJhbGciOiJ
    IUzI1NiJ9.eyJ1c2VyIjp7ImlkI
    joxLCJuYW1lIjoiTHXDrXMgQ29i
    dWNjaSJ9fQ.

    View Slide

  24. eyJ0eXAiOiJKV1QiLCJhbGciOiJ
    IUzI1NiJ9.eyJ1c2VyIjp7ImlkI
    joxLCJuYW1lIjoiTHXDrXMgQ29i
    dWNjaSJ9fQ.
    base64_encode()

    View Slide

  25. eyJ0eXAiOiJKV1QiLCJhbGciOiJ
    IUzI1NiJ9.eyJ1c2VyIjp7ImlkI
    joxLCJuYW1lIjoiTHXDrXMgQ29i
    dWNjaSJ9fQ.

    View Slide

  26. eyJ0eXAiOiJKV1QiLCJhbGciOiJ
    IUzI1NiJ9
    .
    eyJ1c2VyIjp7ImlkIjoxLCJuYW1
    lIjoiTHXDrXMgQ29idWNjaSJ9fQ
    .

    View Slide

  27. Base64URL
    eyJ0eXAiOiJKV1QiLCJhbGciOiJ
    IUzI1NiJ9
    .
    eyJ1c2VyIjp7ImlkIjoxLCJuYW1
    lIjoiTHXDrXMgQ29idWNjaSJ9fQ
    .

    View Slide

  28. + → -

    / → _

    = → (removed)
    TeSJWlQ/
    S4YaOgK5tz7j+3KxBA
    g3HTONa9NP80R+9mY=
    TeSJWlQ_S4YaOgK5tz7
    j-3KxBAg3HTONa9NP80
    R-9mY

    View Slide

  29. function base64url_encode(string $data): string {
    $data = base64_encode($data);

    return rtrim(

    strtr($data, '+/', '-_'),
    '='
    );
    }

    View Slide

  30. function base64url_decode(string $data): string {

    if ($remainder = strlen($data) % 4) {
    $data .= str_repeat('=', 4 - $remainder);
    }
    return base64_decode(

    strtr($data, '-_', '+/')
    );
    }

    View Slide

  31. eyJ0eXAiOiJKV1QiLCJhbGciOiJ
    IUzI1NiJ9
    .
    eyJ1c2VyIjp7ImlkIjoxLCJuYW1
    lIjoiTHXDrXMgQ29idWNjaSJ9fQ
    .

    View Slide

  32. {

    "typ": "JWT",

    "alg": "none"

    }
    {

    "user": {

    "id": 1,

    "name": "Luís Cobucci"

    }

    }

    View Slide

  33. The JSON!
    http://goo.gl/gH0hsx

    View Slide

  34. {

    "typ": "JWT",

    "alg": "none"

    }
    {

    "user": {

    "id": 1,

    "name": "Luís Cobucci"

    }

    }

    View Slide

  35. 401

    Unauthorised
    http://goo.gl/yyZ7oC

    View Slide

  36. Client
    API DB

    View Slide

  37. 1. presents credentials
    POST /auth

    {

    "email": "[email protected]",
    "password": "amazing!"

    }
    Client
    API DB

    View Slide

  38. 1. presents credentials
    2. validates and creates a token
    Client
    API
    - issuer: auth.example.com
    - permitted to: client.example.com
    - expires in 300 seconds
    DB

    View Slide

  39. 1. presents credentials
    2. validates and creates a token
    201 Created

    {

    "token": "…"

    }
    Client
    API DB

    View Slide

  40. 1. presents credentials
    2. validates and creates a token
    3. sends the issued token
    GET /
    Authorization: …
    Client
    API DB

    View Slide

  41. 1. presents credentials
    2. validates and creates a token
    3. sends the issued token
    4. verifies the signature, validates the
    claims and processes the request
    - is it valid?
    - client allowed?
    - expected issuer?
    - can it be used at this moment?
    Client
    API DB

    View Slide

  42. How about OAuth2?

    View Slide

  43. Sessions
    https://goo.gl/KNrl16

    View Slide

  44. file
    Webserver
    Set-Cookie:

    SESSION_ID=123abc

    View Slide

  45. file a
    Webserver
    Client
    SESSION_ID=123abc

    View Slide

  46. file a
    Webserver 1
    Client
    SESSION_ID=123abc
    file b
    Webserver 2
    file c
    Webserver 3
    Load balancer

    View Slide

  47. Webserver 1
    Client
    SESSION=eyJ0eXAiOiJKV1QiLCJhbGciO
    iJIUzI1NiJ9.eyJ1c2VyIjp7ImlkIjoxL
    CJuYW1lIjoiTHXDrXMgQ29idWNjaSJ9fQ
    .hv9V7gBBJPeWMbwFFmRP7clLuof7r9fV
    JzZbLZIxBTs
    Webserver 2 Webserver 3
    Load balancer

    View Slide

  48. ! 1. cannot store private information in
    the session


    2. sessions cannot be (easily)
    invalidated

    3. increased network traffic


    4. race conditions with highly
    concurrent HTTP requests writing to
    session


    5. limit on the amount of data stored in
    session

    View Slide

  49. View Slide

  50. More!!
    https://goo.gl/gEjEMm

    View Slide

  51. https://goo.gl/GB6YkQ
    Let’s investigate it

    View Slide

  52. {

    "typ": "JWT",

    "alg": "none"

    }
    {

    "user": {

    "id": 1,

    "name": "Luís Cobucci"

    }

    }

    View Slide

  53. headers
    {

    "typ": "JWT",

    "alg": "none"

    }
    {

    "user": {

    "id": 1,

    "name": "Luís Cobucci"

    }

    }

    View Slide

  54. headers
    {

    "typ": "JWT",

    "alg": "none"

    }
    {

    "user": {

    "id": 1,

    "name": "Luís Cobucci"

    }

    }
    claims

    View Slide

  55. Base64URL( )

    + "." + 

    Base64URL( )

    + "."
    headers
    claims

    View Slide

  56. headers
    {

    "typ": "JWT",

    "alg": "none"

    }
    {

    "user": {

    "id": 1,

    "name": "Luís Cobucci"

    }

    }
    claims

    View Slide

  57. eyJhbGciOiJub25lIiwidHlwIjo
    iSldUIn0

    .

    eyJ1c2VyIjp7ImlkIjoxLCJuYW1
    lIjoiTHXDrXMgQ29idWNjaSJ9fQ

    .

    View Slide

  58. Can you trust it?
    https://goo.gl/EeeIdu

    View Slide

  59. Base64URL( )

    + "." + 

    Base64URL( )
    headers
    claims
    payload

    View Slide

  60. Base64URL( )

    + "." + 

    Base64URL( )
    headers
    claims
    payload
    = alg( , )
    payload key
    signature

    View Slide

  61. Base64URL( )

    + "." + 

    Base64URL( )

    + "." + 

    Base64URL( )
    headers
    claims
    signature

    View Slide

  62. function jwt_create(
    array $headers,
    array $claims,
    string $key
    ): string {

    $headers = base64url_encode(json_encode($headers));

    $claims = base64url_encode(json_encode($claims));
    $payload = $headers . '.' . $claims;
    $signature = base64url_encode(

    hash_hmac('sha256', $payload, $key, true)

    );
    return $payload . '.' . $signature;
    }

    View Slide

  63. What
    algorithms?
    https://goo.gl/qNTg3D

    View Slide

  64. HS256
    HS384
    HS512
    RS256
    RS384
    RS512
    ES256
    ES384
    ES512
    PS256
    PS384
    PS512
    none
    HMAC
    RSA
    ECDSA
    RSASSA-PSS

    View Slide

  65. HS256
    HS384
    HS512
    RS256
    RS384
    RS512
    ES256
    ES384
    ES512
    PS256
    PS384
    PS512
    none
    HMAC
    RSA
    ECDSA
    RSASSA-PSS

    View Slide

  66. HS256
    HS384
    HS512
    RS256
    RS384
    RS512
    ES256
    ES384
    ES512
    PS256
    PS384
    PS512
    none
    HMAC
    RSA
    ECDSA
    RSASSA-PSS

    View Slide

  67. headers
    {

    "typ": "JWT",

    "alg": "HS256"

    }
    {

    "user": {

    "id": 1,

    "name": "Luís Cobucci"

    }

    }
    claims
    key
    Hello JWT+JWS!

    View Slide

  68. eyJhbGciOiJub25lIiwidHlwIjo
    iSldUIn0

    .

    eyJ1c2VyIjp7ImlkIjoxLCJuYW1
    lIjoiTHXDrXMgQ29idWNjaSJ9fQ

    .

    hv9V7gBBJPeWMbwFFmRP7clLuof
    7r9fVJzZbLZIxBTs

    View Slide

  69. How much data?
    https://goo.gl/eHFQwO

    View Slide

  70. iat (NumericDate)
    exp (NumericDate)
    nbf (NumericDate)
    jti (String)
    iss (StringOrUri)
    aud (StringOrUri[])
    sub (StringOrUri)

    View Slide

  71. iat (NumericDate)
    exp (NumericDate)
    nbf (NumericDate)
    jti (String)
    iss (StringOrUri)
    aud (StringOrUri[])
    sub (StringOrUri)
    case-sensitive

    View Slide

  72. https://goo.gl/bkXMeq
    Revoke tokens?

    View Slide

  73. {

    "user": {

    "id": 1,

    "name": "Luís Cobucci"

    }

    }

    View Slide

  74. {

    "jti": "1245456",

    "exp": 1527417474,

    "user": {

    "id": 1,

    "name": "Luís Cobucci"

    }

    }
    Blacklist Whitelist

    View Slide

  75. PHP libraries!
    https://goo.gl/bGP8u8

    View Slide

  76. View Slide

  77. View Slide

  78. declare(strict_types=1);
    require 'vendor/autoload.php';
    use Lcobucci\JWT\Configuration;
    use Lcobucci\JWT\Signer\Key;
    use Lcobucci\JWT\Signer\Hmac\Sha256;
    return Configuration::forSymmetricSigner(
    new Sha256(),
    new Key('my super secret key')
    );

    View Slide

  79. declare(strict_types=1);
    require 'vendor/autoload.php';
    use Lcobucci\JWT\Configuration;
    use Lcobucci\JWT\Signer\Key;
    use Lcobucci\JWT\Signer\Rsa\Sha256;
    return Configuration::forAsymmetricSigner(
    new Sha256(),
    new Key('file://private.pem', 'testing'),
    new Key('file://public.pem')
    );

    View Slide

  80. declare(strict_types=1);
    $config = require 'config.php';

    assert($config instanceof \Lcobucci\JWT\Configuration);
    $signer = $config->getSigner();
    $key = $config->getSigningKey();
    $token = $config->createBuilder()
    ->withClaim('uid', 1)
    ->getToken($signer, $key);

    View Slide

  81. declare(strict_types=1);
    $config = require 'config.php';

    assert($config instanceof \Lcobucci\JWT\Configuration);

    $signer = $config->getSigner();
    $key = $config->getSigningKey();
    $token = $config->createBuilder()
    ->withClaim('uid', 1)
    ->identifiedBy(bin2hex(random_bytes(16)))
    ->getToken($signer, $key);

    View Slide

  82. declare(strict_types=1);
    $config = require 'config.php';

    assert($config instanceof \Lcobucci\JWT\Configuration);

    $signer = $config->getSigner();
    $key = $config->getSigningKey();
    $token = $config->createBuilder()
    ->withClaim('uid', 1)
    ->identifiedBy(bin2hex(random_bytes(16)))
    ->issuedBy('https://foo.bar')
    ->getToken($signer, $key);

    View Slide

  83. declare(strict_types=1);
    $config = require 'config.php';

    assert($config instanceof \Lcobucci\JWT\Configuration);


    $signer = $config->getSigner();
    $key = $config->getSigningKey();
    $token = $config->createBuilder()
    ->withClaim('uid', 1)
    ->identifiedBy(bin2hex(random_bytes(16)))
    ->issuedBy('https://foo.bar')

    ->permittedFor('https://client1.bar')

    ->permittedFor('https://client2.bar')
    ->getToken($signer, $key);

    View Slide

  84. declare(strict_types=1);
    $config = require 'config.php';

    assert($config instanceof \Lcobucci\JWT\Configuration);
    $signer = $config->getSigner();
    $key = $config->getSigningKey();
    $now = new DateTimeImmutable();
    $token = $config->createBuilder()
    ->withClaim('uid', 1)
    ->identifiedBy(bin2hex(random_bytes(16)))
    ->issuedBy('https://foo.bar')

    ->permittedFor('https://client1.bar')

    ->permittedFor('https://client2.bar')

    ->issuedAt($now)

    ->canOnlyBeUsedAfter($now->modify('+5 minutes'))

    ->expiresAt($now->modify('+1 hour'))
    ->getToken($signer, $key);

    View Slide

  85. eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9

    .

    eyJ1aWQiOjEsImp0aSI6ImFhMzk3YzA2ZDUwZmRhNjYyYWUwZGE4OTU2ODdmN
    zY3IiwiaXNzIjoiaHR0cHM6Ly9mb28uYmFyIiwiYXVkIjpbImh0dHBzOi8vY2
    xpZW50MS5iYXIiLCJodHRwczovL2NsaWVudDIuYmFyIl0sImlhdCI6IjE0OTU
    xNzg5MDQuODY4ODc5IiwibmJmIjoiMTQ5NTE3OTIwNC44Njg4NzkiLCJleHAi
    OiIxNDk1MTgyNTA0Ljg2ODg3OSJ9

    .

    jwXzXjm8cU92yxP3XcENg_ZnDvW1MkRTzSoaAwOYCTlSdQ5rv-
    dCLn_7_XPLHSuiACt_aFTnB093GYTpJQKRnqIFPYteK2jVnQALXNPxntnp-
    v6SMiFBxofCaVSjgKTWdqkWB4agWrTR77HK_iKdFoZMIdpr8UUBJatkc_MCoD
    vDMtuDRXwIEBfjs9baICtBvTZyDD7iiMmF4F_qvp2mWd_Qy93gZCrePKAJsgY
    -
    sujg84iQFOs-6I3GjybzA0U0Y_bTmCmQHfhRUX5_gL21bZxBFef38OFKW73Vx
    ehBxM4Ok_nWRbGY7ehsMBshXkJQfp97TJ1cV35a9zyAVXC04A

    View Slide

  86. {

    "typ": "JWT",

    "alg": "RS256"

    }
    {

    "uid": 1,
    "jti": "aa397c06d50fda662ae0da895687f767",
    "iss": "https://foo.bar",
    "aud": ["https://client1.bar", “https://client2.bar”],
    "iat": "1495178904.868879",
    "nbf": "1495179204.868879",
    "exp": "1495182504.868879"

    }

    View Slide

  87. declare(strict_types=1);
    $config = require 'config.php';

    assert($config instanceof \Lcobucci\JWT\Configuration);

    $jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOjEsImp0aSI6ImFh'
    . 'Mzk3YzA2ZDUwZmRhNjYyYWUwZGE4OTU2ODdmNzY3IiwiaXNzIjoiaHR0cHM6L'
    . 'y9mb28uYmFyIiwiYXVkIjpbImh0dHBzOi8vY2xpZW50MS5iYXIiLCJodHRwcz'
    . 'ovL2NsaWVudDIuYmFyIl0sImlhdCI6IjE0OTUxNzg5MDQuODY4ODc5IiwibmJ'

    . 'mIjoiMTQ5NTE3OTIwNC44Njg4NzkiLCJleHAiOiIxNDk1MTgyNTA0Ljg2ODg3'
    . 'OSJ9.jwXzXjm8cU92yxP3XcENg_ZnDvW1MkRTzSoaAwOYCTlSdQ5rv-dCLn_7'

    . '_XPLHSuiACt_aFTnB093GYTpJQKRnqIFPYteK2jVnQALXNPxntnp-v6SMiFBx'

    . 'ofCaVSjgKTWdqkWB4agWrTR77HK_iKdFoZMIdpr8UUBJatkc_MCoDvDMtuDRX'

    . 'wIEBfjs9baICtBvTZyDD7iiMmF4F_qvp2mWd_Qy93gZCrePKAJsgY-sujg84i'

    . 'QFOs-6I3GjybzA0U0Y_bTmCmQHfhRUX5_gL21bZxBFef38OFKW73VxehBxM4O'

    . 'k_nWRbGY7ehsMBshXkJQfp97TJ1cV35a9zyAVXC04A';


    $token = $config->getParser()->parse($jwt);

    View Slide

  88. declare(strict_types=1);
    use Lcobucci\Clock\SystemClock;

    use Lcobucci\JWT\Validation\Constraint;
    $config = require 'config.php';

    assert($config instanceof \Lcobucci\JWT\Configuration);
    $signer = $config->getSigner();
    $key = $config->getVerificationKey();

    $token = $config->getParser()->parse('eyJ0eNiJ9 (...)');
    $constraints = [
    new Constraint\IssuedBy('https://foo.bar', 'https://bar.foo'),
    new Constraint\PermittedFor('https://client2.bar'),

    new Constraint\ValidAt(new SystemClock()),

    new Constraint\SignedWith($signer, $key)

    ];


    $config->getValidator()->assert($token, ...$constraints);

    View Slide

  89. declare(strict_types=1);
    use Lcobucci\Clock\SystemClock;

    use Lcobucci\JWT\Validation\Constraint;
    $config = require 'config.php';

    assert($config instanceof \Lcobucci\JWT\Configuration);

    $signer = $config->getSigner();
    $key = $config->getVerificationKey();

    $token = $config->getParser()->parse('eyJ0eNiJ9 (...)');
    $constraints = [
    new Constraint\IssuedBy('https://foo.bar', 'https://bar.foo'),
    new Constraint\PermittedFor('https://client2.bar'),

    new Constraint\ValidAt(new SystemClock()),

    new Constraint\SignedWith($signer, $key)

    ];


    var_dump($config->getValidator()->validate($token, ...$constraints));

    View Slide

  90. Criticism
    https://goo.gl/wfYBKA

    View Slide

  91. In summary…
    https://goo.gl/TVhdnm

    View Slide

  92. JWT
    To infinity

    & beyond!
    authentication
    Luís Cobucci

    @lcobucci
    https://goo.gl/gbd3H5

    View Slide

  93. Thanks!
    @lcobucci

    View Slide