Subject: [OAUTH-WG] DPoP Binding JWT proposal

From: Dick Hardt <[email-masked]>
Date: Fri, 6 Nov 2020 14:12:07 -0800

Hello

After reviewing the DPoP spec, and reflecting on implementations I have
worked with, I wanted to see if there was interest in a DPoP Binding JWT.

The use case is to enable existing deployments to add support for DPoP
without having to replace their existing refresh token and access tokens,
and the processing of them as the DPoP Binding JWT processing can be added
as an independent software layer.

The processing overhead is minimized as the DPoP Binding JWT
verification can be cached for an access token,
adding only one JWT verification for the lifetime of the access token.

DPoP Binding JWTs using asymmetric cryptographic algorithms, provide the
increased security of public / private key for existing deployments using
access tokens signed with shared secrets such as HMAC.

/Dick

*X. DPoP Binding JWT*
    Deployments that do not want to modify their existing access tokens or
resource tokens to contain
    the DPoP thumbprint can include DPoP Binding JWTs in the response from
the AS and present them in
    calls to the RS. A DPoP Binding JWT contains the DPoP thumbprint and a
hash of the access token
    or refresh token, and is signed by the AS.

    The use of DPoP Binding JWTs enables existing deployments to add
proof-of-possession assurance to
    existing deployments by adding a middle layer service or software
without modifying the processing
    of refresh tokens or access tokens.

*X.1 DPoP Binding JWT Syntax*
    * "typ": type header, value "dpop-binding+jwt"

    * "jti": unique id
    * "iat": time created
    * "jkt": JWK SHA-256 Thumbprint of the DPoP public key

    If binding an access token
        * "ath": SHA-256 hash of the access token

    If binding an refresh token
        * "rth": SHA-256 hash of the refresh token

    Example DPoP Binding JWT for an access token:

    {
        "typ":"dpop-binding+jwt",
        "alg":"ES256",
        "jwk": {
        "kty":"EC",
        "x":"l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs",
        "y":"9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA",
        "crv":"P-256"
        }
    }.{
        "jti":"-BwC3ESc6acc2lTc",
        "iat":1562262616,
        "jkt":"0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
        "ath":"N0d2HglBV3uiguA4I0ZcOCORZNYy-DWpqq30jZyJGHT"
    }

*X.2 Checking DPoP Bindings*
    Check the DPoP Binding JWT is valid
    Check the DPoP Binding JWT "jkt" value matches the thumbprint of the
DPoP public key
    Check the DPoP Binding JWT "ath" value matches the SHA-256 hash of the
access token
      or
    Check the DPoP Binding JWT "rth" value matches the SHA-256 hash of the
refresh token

*X.3 Token Response*
    The AS sets the "token_type" parameter to "DPoP-Binding".
    The AS returns the DPoP Binding JWT for the access token in the
"access_token_binding" parameter,
    and the DPoP Binding JWT for the refresh token in the
"refresh_token_binding" parameter.

     HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "access_token_binding":"eyJ0eXAiOiJkcG9w....",
       "token_type":"DPoP-Binding",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA"
       "refresh_token_binding":"eyJ0eXAiOiJkcG9w....."
       "example_parameter":"example_value"
     }

*X.4 Resource access*
    The client presents the access token DPoP Binding JWT in the
"DPoP-Binding" HTTP header.

    GET /protectedresource HTTP/1.1
    Host: resource.example.org
    Authorization: DPoP eyJhbGciOiJFUzI1NiIsImtpZCI6IkJlQUxrYiJ9.eyJzdWI
        iOiJzb21lb25lQGV4YW1wbGUuY29tIiwiaXNzIjoiaHR0cHM6Ly9zZXJ2ZXIuZXhhbX
        BsZS5jb20iLCJhdWQiOiJodHRwczovL3Jlc291cmNlLmV4YW1wbGUub3JnIiwibmJmI
        joxNTYyMjYyNjExLCJleHAiOjE1NjIyNjYyMTYsImNuZiI6eyJqa3QiOiIwWmNPQ09S
        Wk5ZeS1EV3BxcTMwalp5SkdIVE4wZDJIZ2xCVjN1aWd1QTRJIn19.vsFiVqHCyIkBYu
        50c69bmPJsj8qYlsXfuC6nZcLl8YYRNOhqMuRXu6oSZHe2dGZY0ODNaGg1cg-kVigzY
        hF1MQ
    DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik
        VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR
        nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE
        QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiJlMWozVl9iS2ljOC1MQUVCIiwiaHRtIj
        oiR0VUIiwiaHR1IjoiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLm9yZy9wcm90ZWN0Z
        WRyZXNvdXJjZSIsImlhdCI6MTU2MjI2MjYxOH0.lNhmpAX1WwmpBvwhok4E74kWCiGB
        NdavjLAeevGy32H3dbF0Jbri69Nm2ukkwb-uyUI4AUg1JSskfWIyo4UCbQ
    DPoP-Binding: eyJ_an_example_DPoP_binding_JWT_0eXAiOiJkcG9wK2p3dCIsI
        VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR
        nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE
        QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiJlMWozVl9iS2ljOC1MQUVCIiwiaHRtIj
        oiR0VUIiwiaHR1IjoiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLm9yZy9wcm90ZWN0Z
        WRyZXNvdXJjZSIsImlhdCI6MTU2MjI2MjYxOH0.lNhmpAX1WwmpBvwhok4E74kWCiGB
        NdavjLAeevGy32H3dbF0Jbri69Nm2ukkwb-uyUI4AUg1JSskfWIyo4UCbQ

ᐧ

---

From: Dick Hardt <[email-masked]>
Date: Mon, 30 Nov 2020 08:28:45 -0800

Pushing this to the top of the stack in case there is interest in
separating the binding mechanism from the RT / AT so that existing RTs /
ATs can be used.
ᐧ