Istio as BFF in the Auth Code Flow With PKCE

Hi, I am wondering:
Can we use istio as the BFF described in the BCP ?

I am new to istio, from what I already learned from istio docs, it seems istio can help to validate JWT tokens to insure client have the right to access some resource. but for my case, SPA + Backend, SPA is browser based, it’s deprected to store Access Token in client side, so the IETF BCP suggest a BFF to handle this. Peronally , I want to avoid implementing a seprate backend to do this, I think some gateway or service mesh can take care of these concerns, same as loading balancing, logging, tracing, these shared feature should be provided by PaaS.

Does istio already support this?

Hi,

I am a newby and I am not affiliated with the Istio project…

I don’t really understand why “it’s deprecated to store Access Token on the client side” and how you can store it elsewhere?
> Unless you’re talking about storing the token of a hosted service outside the BFF cluster. User A → Browser → token A → BFF → Token B → External service B. (if yes look at the end)

According to: JSON Web Token - Wikipedia
The backend generates a token using the client credentials, and the client uses the token to access the backend resources, so the token must be stored on the client…

If that helps, here’s how I do it with Istio:

  1. I have an “authenticator” in my backend that uses Jose to generate a token after verifying the client’s credentials (using a secure connection: HTTPS). But you can use an external authenticator like Google or any social network ones.
  2. The client stores the token on the client browser’s memory, and the browser’s isolation ensures that no other tab can access it.
  3. When the client calls the back-end service, it injects this token on the request header.
    Example: Authorization: Bearer «place the token here».
  4. The istio ingress is configured to verify the token; the documentation is here: Istio / JWT Token
    a) Replace the “issuer” value with your own or Google’s one.
    b) Replace the JWKS (only public part) with your own (or Google’s one. You can also store it as a secret).
    c) If you use your own authenticator, make sure that the subject (sub) is the same in the key and the token…

If you have any problems, go to https://jwt.io and use the webui to verify the token and keys.

If you want to customize the header, look below at “fromHeaders”.

If you want to retrieve a decoded version of the token payload in your service, see “outputPayloadToHeader” and “forwardOriginalToken” below, it may be useful to retrieve the user type for example.

apiVersion: "security.istio.io/v1beta1"
kind: "RequestAuthentication"
metadata:
  name: authenticator-jwks
  namespace: istio-system
spec:
  selector:
    matchLabels:
     istio: ingressgateway
  jwtRules:
  - issuer: "auth@myapp.io"
    jwks: |
      { "keys": [{"kty":"RSA","n":"lkp5....gHpCQ","e":"AQAB","kid":"4d58...ea6","alg":"RS256"}]}
    fromHeaders:
      - name: Authorization
        prefix: "Bearer "
    outputPayloadToHeader: x-jwt
    forwardOriginalToken: true

To improve the internal cluster security (man in the middle), do not forget to enable STRICT mTLS, but do this step by step this part can be tricky…


For the external service case, I do not know of any mechanism in Istio to do so and I do not think it is the role of the ingress nor the egress (the token and API key are often user-specific) but rather that of the BFF; because in this case it is the BFF the client of the service. I don’t know what framework you’re using for the BFF, but I guess there must be a notion of user session. When the user logs in, I would retrieve the token or API key from a database and add it to the user session data (memory or cache/redis). Like this when from a request to the outside the BFF will find it easily…

You may lock at: Citadel is also one of the main components in Istio service mesh. It provides strong service-to-service and end-user authentication with built-in identity and credential management. This can be used to upgrade unencrypted traffic in the service mesh. Using Citadel, operators can enforce policies based on service identity rather than on network controls.

see this article

it’s deprected to store Access Token in client side

It’s my fault, did not describe it correctly. Here I mean store Access Token in SPA, the browser.

from above article:

  • Tokens are available in the browser

As tokens are used when communicating with APIs, they are available in the browser. Consequently, they can be obtained by common Open Web Application Security Project (OWASP) defined attacks like Cross-Site Scripting (XSS).

  • Storage mechanisms are unsafe

It is not possible to store something in the browser safely over a long time without using a back end to secure it. Any browser-based storage mechanism is susceptible to attacks.

and they suggest something like this, which I think is comply with the IETF Best Current Practice

my backend can be considered as API in above picture, and I am going to deploy it on istio, so instead of implment a seprate BFF(the Token handler in above picture), I am looking for a solution with istio.

Hope you can understand my poor english. :sweat_smile:

Hi, No problemo for your English, I am french mine is worse ^_^…

I agree with you, browser long storage is unsafe…

I don’t have the time during works days to look closely, but this weekend I will look closer the article and your post…

Regards,

Arnaud

Hi,

I quickly read the article, currently, I don’t think Istio provides the kind of service you need.

But my 1st idea seems to be the right one:

1 - Secure your connection between the ‘frontend’ and the ‘backend’ with JWT (included in Istio) and you insert into the payload of the jwt the ID of your client/user.

2 - Add a database (backend) that will allow you to store the token or API key associated with the ID of your client/user and a service.

3a – If these services are internal to you to see how you want to manage the access authorization of this service with this client/user, but in the end, you will have to store the key in the database and associate it with the user ID and the service.

3b – If it is a ‘third party’ service, you will have to use an external API to retrieve the token or API key and store it in the BDD, ‘keycloak’ could simplify the work.

4 – In the ‘backend’ you will have to write a kind of proxy that will intercept requests from ‘frontend’ to services. The purpose of this component will be to retrieve the token or API key for the ‘third party’ service associated with the customer ID and make the call to this service.

For more information on the verification of the JWT and the injection of the JWT payload into the header by the ingress d’istio, see my 1st answer.

Finally, check the performance and if the call is too slow, use a cache to speed up the recovery of the key associated with the user/service combo.

Regards,

Arnaud