In the previous Blog
post, we covered how
Gloo can be used to authenticate users with OIDC and how it can process the JWT token returned by the identity provider.
The JWT token was stored as a cookie in the web browser and sent with each HTTP request as a header.
We configured Gloo to manipulate each request as follow:
- extract the token from the cookie header
- validate the token
- extract claims from the token
- add new headers based on the claims (for example, a header with the email of the user)
- apply RBAC rules to determine if the request should be authorized (based on the email, method, path, ...)
This workflow works well, but it has both pros and cons:
- pro: the cookie is sent with each HTTP request (because it's stored as a cookie), so we can do all these nice manipulations.
- con: even if the cookie is stored with the attributes
Secure
and HttpOnly
, some users prefer to avoid any sensitive information in the web browser.
- con: in some cases, there are many claims in the token which can cause the size of the cookie to exceed the 4 KB allowed by the web browers.
Caching the JWT token in Redis
To avoid storing the cookie in the web browser, you can enable caching when creating the Gloo
AuthConfig
:
apiVersion: enterprise.gloo.solo.io/v1
kind: AuthConfig
metadata:
name: google-oidc
namespace: gloo-system
spec:
configs:
- oauth2:
oidcAuthorizationCode:
appUrl: https://mydomain.com
callbackPath: /callback
clientId: $CLIENT_ID
clientSecretRef:
name: google
namespace: gloo-system
issuerUrl: https://accounts.google.com
scopes:
- email
session:
failOnFetchFailure: true
redis:
cookieName: session
options:
host: redis.gloo-system.svc.cluster.local:6379
As you can see, the token will be stored in Redis.
Let's start with a simple
VirtualService
:
apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
name: default
namespace: gloo-system
spec:
sslConfig:
secretRef:
name: upstream-tls
namespace: gloo-system
virtualHost:
domains:
- '*'
routes:
- matchers:
- prefix: /
routeAction:
single:
upstream:
name: default-httpbin-8000
namespace: gloo-system
options:
extauth:
configRef:
name: google-oidc
namespace: gloo-system
If you try to access the application using your browser, here is the output you should get:
{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "fr-fr",
"Content-Length": "0",
"Cookie": "session=6DDMJFK2P35EQ42LZFUSBBHTZ3Y5X6CWKNJ33HHDSN2PW3HFNRGYN47UKM5BOE362VGSMW4VCMK7ZNOK7D45EXIKKDG3HGJOWXL7SWQ=",
"Host": "mydomain.com",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15",
"X-Envoy-Expected-Rq-Timeout-Ms": "15000",
"X-User-Id": "https://accounts.google.com;117577190223680183681"
},
"origin": "192.168.149.8",
"url": "https://mydomain.com/get"
}
The web browser is still sending a cookie with each request, but this cookie doesn't contain the token anymore.
It a session cookie that allows Gloo to retrieve the JWT token from Redis.
Everything works well, but we can't access the token anymore and perform all the nice manipulations we were able to perform before. So, how will the backend application able to determine who the user is if it needs this information ?
Forward the JWT token upstream
Gloo provides an option to create a new header with this token when it retrieves it from Redis.
Let's update the
AuthConfig
to enable this option:
apiVersion: enterprise.gloo.solo.io/v1
kind: AuthConfig
metadata:
name: google-oidc
namespace: gloo-system
spec:
configs:
- oauth2:
oidcAuthorizationCode:
appUrl: https://mydomain.com
callbackPath: /callback
clientId: $CLIENT_ID
clientSecretRef:
name: google
namespace: gloo-system
issuerUrl: https://accounts.google.com
scopes:
- email
session:
failOnFetchFailure: true
redis:
cookieName: session
options:
host: redis.gloo-system.svc.cluster.local:6379
headers:
id_token_header: "jwt"
Here is the output you should get if you refresh the web page:
{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "fr-fr",
"Content-Length": "0",
"Cookie": "session=6DDMJFK2P35EQ42LZFUSBBHTZ3Y5X6CWKNJ33HHDSN2PW3HFNRGYN47UKM5BOE362VGSMW4VCMK7ZNOK7D45EXIKKDG3HGJOWXL7SWQ=",
"Host": "mydomain.com",
"Jwt": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImYwOTJiNjEyZTliNjQ0N2RlYjEwNjg1YmI4ZmZhOGFlNjJmNmFhOTEiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI2MzUzODgzNDA1MjEtMHNtNzFtZ29rZXFmbGs0ajlyZGJncHQyNnRkbGJybjMuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI2MzUzODgzNDA1MjEtMHNtNzFtZ29rZXFmbGs0ajlyZGJncHQyNnRkbGJybjMuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTc1NzcxOTAyMjM2ODAxODM2ODEiLCJlbWFpbCI6ImRqYW5ub3RAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF0X2hhc2giOiJOWHVKNWpKZnhkTGVhTHFDLUtPMF9nIiwiaWF0IjoxNjA0NTY1MDg2LCJleHAiOjE2MDQ1Njg2ODZ9.wFrDI_pXNgOzOWKEt0ou0MNfsWUbVWP4KtnkyuqET38wia6c3gX4g5Ck2GPHBy1ZuKC9luc1SK3n11G9VvhmiR94ysk6kWJDtK1uEYv6MNt4KLFtiO9iQ0Mx8yiqXgKPFdGEssqLbE7ifQtko5YJA8qARI6OwPxHt3FwjHYI8G_qJmiTqcJGwXi5yPj47rXuwUc7akEwFga5w4EP46Xsv7onxnoMbeM8w4zJNncVzm9qruf56aFGm9vWgCl3cdIV6fDZfFZkBrgt4r4S-UADfrqqogvSe9RajXxkiln_TKtlrVXha_--pfvrhgf4uqyY4sfwTj2qrjHsiDUNbDbBMQ",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15",
"X-Envoy-Expected-Rq-Timeout-Ms": "15000",
"X-User-Id": "https://accounts.google.com;117577190223680183681"
},
"origin": "192.168.149.8",
"url": "https://mydomain.com/get"
}
Great ! Now you have your JWT token in a header and you can perform all the manipulations like in the previous Blog
post.
Update your
VirtualService
as follow:
apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
name: default
namespace: gloo-system
spec:
sslConfig:
secretRef:
name: upstream-tls
namespace: gloo-system
virtualHost:
domains:
- '*'
routes:
- matchers:
- prefix: /
routeAction:
single:
upstream:
name: default-httpbin-8000
namespace: gloo-system
options:
extauth:
configRef:
name: google-oidc
namespace: gloo-system
headerManipulation:
requestHeadersToRemove:
- "cookie"
jwt:
providers:
google:
issuer: https://accounts.google.com
tokenSource:
headers:
- header: Jwt
claimsToHeaders:
- claim: email
header: x-solo-claim-email
- claim: email_verified
header: x-solo-claim-email-verified
jwks:
remote:
url: https://www.googleapis.com/oauth2/v3/certs
upstreamRef:
name: google-jkws
namespace: gloo-system
rbac:
policies:
viewer:
permissions:
methods:
- GET
pathPrefix: /get
principals:
- jwtPrincipal:
claims:
email: djannot@gmail.com
Here is the output you should get if you refresh the web page:
{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "fr-fr",
"Content-Length": "0",
"Host": "mydomain.com",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15",
"X-Envoy-Expected-Rq-Timeout-Ms": "15000",
"X-Solo-Claim-Email": "djannot@gmail.com",
"X-Solo-Claim-Email-Verified": "true",
"X-User-Id": "https://accounts.google.com;117577190223680183681"
},
"origin": "192.168.149.8",
"url": "https://mydomain.com/get"
}
What happens here ?
Gloo gets the token from the
Jwt
header, validates it, extracts some claims from it and add headers for these claims. Finally, it applies RBAC rules based on the claims.
So,
we now have the best of both worlds: the JWT token isn't stored in the web browser anymore, but we can perform all the manipulations we want from it.
Logout
Gloo also supports specifying a logout url. When specified, accessing this url will trigger a deletion of the user session.
You can enable this option by updating the
AuthConfig
as follow:
apiVersion: enterprise.gloo.solo.io/v1
kind: AuthConfig
metadata:
name: google-oidc
namespace: gloo-system
spec:
configs:
- oauth2:
oidcAuthorizationCode:
appUrl: https://mydomain.com
callbackPath: /callback
clientId: $CLIENT_ID
clientSecretRef:
name: google
namespace: gloo-system
issuerUrl: https://accounts.google.com
scopes:
- email
session:
failOnFetchFailure: true
redis:
cookieName: session
options:
host: redis.gloo-system.svc.cluster.local:6379
headers:
id_token_header: "x-token"
logoutPath: /logout
Get Started with Gloo
Gloo is available in open source and enterprise editions addressing a wide range of edge and API gateway use cases. Learn more about Gloo by visiting the additional resources below.