Re: [OAUTH-WG] I-D Action: draft-ietf-oauth-jwt-introspection-response-08.txt

Travis Spencer <> Wed, 16 October 2019 14:24 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 06D8C12086F for <>; Wed, 16 Oct 2019 07:24:11 -0700 (PDT)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -1.899
X-Spam-Status: No, score=-1.899 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001] autolearn=ham autolearn_force=no
Authentication-Results: (amavisd-new); dkim=pass (2048-bit key)
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id T95Jm3wr4vPP for <>; Wed, 16 Oct 2019 07:24:08 -0700 (PDT)
Received: from ( [IPv6:2607:f8b0:4864:20::c35]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by (Postfix) with ESMTPS id B5927120890 for <>; Wed, 16 Oct 2019 07:24:08 -0700 (PDT)
Received: by with SMTP id e205so8703828ywc.7 for <>; Wed, 16 Oct 2019 07:24:08 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20150623; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc:content-transfer-encoding; bh=vnaMHLoNaRhKZGPp6VFA1kyxdCAPhiGTfGKxPZcWDYo=; b=Izd0KAokeRlkgjgJI3b7czRmeUPwjcZ2IP03yQf5axgSc2hOL23jMHSVWapbAfzMFi RNSPgEc+ycl+J4UtNzyQ6494t8USNmThFcGK4uxdOOsv/BnPBFQ9HJVuG7OP+2UO+Uj5 LmLxQvK61gcuRgPzV0XS9f/gt4ZOovrEIKzPfHT65+AU3ZUoo3HTM30tcqR1PPbhajo/ 2wLoBF7ORow31zbwVE22pfzkiop8C+Q+tXEZsrxZ3Y8dpCHTJzZDLaEEcqYE/vK226aP 69iQYEM6zZUs3rJf3uAy7GhAmU/uVyA9b1o3LgN4xWKyn64tcAyLOq0b5hfmHMnlmOqj mHwA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=vnaMHLoNaRhKZGPp6VFA1kyxdCAPhiGTfGKxPZcWDYo=; b=AYh5j1L+WSdqiJNn4ybVaraE3Sx5GB6VXu4u207Ajs1iCb74YMKUDaQpKIrNCrApvX 6U+q7ho+yOEmX59Dz+z2RHLJoB0FhlTTHmfQTAa6WqObMi4fq04lwAhcUWHnNnEnZGoM jjdVi85MfTZtJKE/yuRAn1h2UlPaCPPbkL5KX1mDQ45Sw0pXvVs6sq+VmZrIWI+34pxk 6ycCg9Mj2/cu7lLki4+mIejLt8ucYTA1VHKUdW5rHy9LhbtLlLr+vvOSdC8YzgUJXJdU RqB5C2cbcJroCCaBLVkuTtGabQoFa1rIuuUGO7lGqLLlPijkNT1f0NhXx7Dzic0buaYj fVpw==
X-Gm-Message-State: APjAAAWhtl1ZEuM2ZpnZaOUrNhFtsCuKY6tpG3mxbq6TDz59ltDteNRs grz5umuLpwjX2068hMKdyZgC3L4ISwFqxGvU3yGbk3wjM4/CEg==
X-Google-Smtp-Source: APXvYqy/Pm5QOdqr8Hh0NR1ohWYL/8eGxNe18MEzVeLOqQPlYDb2ym9+VmtLXdNqeOIIRCgnKBMmILCWy2M7rGQ+lIA=
X-Received: by 2002:a81:f201:: with SMTP id i1mr19796504ywm.69.1571235847520; Wed, 16 Oct 2019 07:24:07 -0700 (PDT)
MIME-Version: 1.0
References: <>
In-Reply-To: <>
From: Travis Spencer <>
Date: Wed, 16 Oct 2019 16:23:56 +0200
Message-ID: <>
To: Torsten Lodderstedt <>
Cc: oauth <>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Archived-At: <>
Subject: Re: [OAUTH-WG] I-D Action: draft-ietf-oauth-jwt-introspection-response-08.txt
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: OAUTH WG <>
List-Unsubscribe: <>, <>
List-Archive: <>
List-Post: <>
List-Help: <>
List-Subscribe: <>, <>
X-List-Received-Date: Wed, 16 Oct 2019 14:24:11 -0000

On Sun, Oct 6, 2019 at 3:31 PM Torsten Lodderstedt
<> wrote:
> Hi Travis,

Hey there, Torsten. Sorry for the slow reply. Still jet lagged ;-)

> > On 26. Sep 2019, at 11:26, Travis Spencer <> wrote:
> Do others have an opinion about this?

> > * Instead of issuing an expired JWT (or in addition) I think it should
> > be valid for the AS to reply with a 201, no content.
> Inline with RFC 7662, the AS always provides data to the RS even in case the introspected access token is expired.

Sure, but is that a good line to follow? The client said it accepts
application/jwt, but the server returns application/json. This breaks
HTTP. (I know that that HTTP allows the server to return a different
media type than the one that was requested if there is only one
representation of the resource, but this is not the case here.) So, to
do this in a way that doesn't break (my understanding of) HTTP, the
client would have to accept both application/jwt and application/json.
Because the status code isn't helpful in determining which, the body
has to parsed based on the content-type response header value. I think
this makes it harder on the consumer than it needs to be and
undoubtedly slower.

> We clarified the intention of this draft due to various feedback (IESG review and other postings on the list). It is supposed to provide a JWT encoded introspection response and not a transformed access token.

I continue (perhaps out of will, I admit) not to see how what I'm
asking for a transformation and not a re-encoding of the same.

> The main differences lay in the existence of the “active“ claim and the different „iat“ values.

The addition of the active claim is a change, I admit that. The iat
claim could be the same as the original though.

> In order to prevent JWT confusion, the JWT shall be restricted to the originator of the introspection call.

In section 5, the draft has this: "The value of the 'aud' claims MUST
identify the resource server receiving the token introspection
response." By resource server here, does it mean, literally, the
caller? RFC 6749 seems to pin that down to one "server" so I think so.
If so, this is different from what's commonly used for audience (or at
least "common" among my experiences). As defined in the JWT spec
(, "[t]he 'aud'
(audience) claim identifies the recipients that the JWT is intended
for....The interpretation of audience values is generally application
specific." This divergence is confusing. I didn't notice it on first
(or second) read, and highly recommend converging these. I think the
JWT definition makes this spec more useful.

> This prevents your use case, but how should we distinguish this from access token replay/abuse?

As you say in section 8.1: "such an attack can be prevented like any
other token substitution attack by restricting the audience of the
JWT." I just think the audience that is defined in this spec is too
narrow. Audience is more like a domain than a web service client
(e.g., the introspection API client). I see the gateway and the
microservices behind it as the same Resource Server with the same
audience if they are all in the security domain. I see the gateway as
being able to straddle multiple audiences though because it could be
fronting multiple clusters of microservices that are in different
domains (i.e., have different audiences). This straddling of different
domains means the gateway either has a different audience or multiple.

> Also, the JWT produced cannot be sender constrained, which even more makes its use as an access token unadvisable.

Sender constrained tokens do provide additional security properties
that are desirable in some cases, but they are not the only kind that
are advisable. It depends on the situation, right?

> In my perception, your proxy transforms the token to make it easier consumable by the target RS.

This is one of the drivers for what I'm advocating: simple API development.

> I see two ways to approach it:
> 1) There is a (yet to be specified) function at the AS that transforms an opaque access token into an JWT-based access token while preserving its audience and other properties (like sender constraints). The proxy itself requires authorization to request that functionality but is not an audience. The access token might even be encrypted for the target RS and be unreadable for the proxy.

This hypothetical spec would vary from this one in what ways exactly?
That's not a facetious question, but something I think we should
honestly catalog. You listed some ideas below, but I need to think
more about these. That gap will help us make informed decisions and
relates to Justin's question about the gap to Token Exchange as well.
See my concern below about how we fill this gap.

> Open: How would one implement sender constrained access tokens in that case? I’m asking since the receiving RS obviously has no access to the information from the TLS handshake since TLS termination happens at the proxy (or even in before the request hits the proxy). The RS would need to get provided with the cert fingerprint via a trustworthy header, i.e. the RS must be aware of the fact it sits behind a proxy.

This is unfortunately the typical case even with the mTLS draft. This
is because SSL is almost never terminated by the AS; in my experience,
TLS termination is instead handled by some very fast proxy.[1] In such
cases, the proxy will pass the cert through to the AS in some
undefined HTTP header with some undefined encoding. The mTLS spec
should have defined this IMO, as it prevents interop for a primary use
case -- sender constrained tokens.

In the case of introspection, I think this verification of the
confirmation method is another aid the proxy could provide to the
microservice. The proxy climbed the chain as it terminated SSL,
fetched CRLs/OCSPs, called LDAP server to get intermediate certs, etc.
Verifying the hash of the cert is not hard for it do as well. If the
proxy doesn't want to parse the body of the introspection HTTP
response though, it will have to forward the cert. The HTTP header and
encoding used is undefined, and that is unfortunate for the sake of
interop. For proxy auth though, we have the HTTP spec, so that could
be leveraged.

> 2) If that’s the case, the RS could also process the token introspection response as received by the proxy. In order to check the audience restriction, the introspection response would need to contain another claim containing the original audience claims of the introspected access token. You could build that on top of draft-ietf-oauth-jwt-introspection-response. What would it take?

This is my concern: we end up with a lot of specs:

1. Introspection RFC
2. JWT introspection RFC
3. Token exchange
4. This hypothetical RFC that profiles #1, #2 and/or #3

Seems overkill. Can't we make more general specs that cover more use
cases? If we don't, the cannon will be so extensive that it'll be
unpredictable for many. This could impede adoption.

[1] I have only come across a situation where the AS terminated SSL
one time, and that was because its mutual TLS impl of the AS didn't
allow for cert-based auth unless it did. (This wasn't Curity which
allows for proxy-based mTLS but some other product.) The customer
reluctantly allowed it and only did TLS-based routing in the proxy.