Google Cloud Using AD FS access tokens for workload identity federation

Workload identity federation supports OpenID Connect, so it should be compatible with AD FS. But until recently, workload identity federation didn’t work with AD FS-issued access tokens – only ID tokens worked properly. What was the issue there?

For ID Tokens, OpenID Connect is pretty specific about their format: They need to be JSON Web Tokens (JWTs), they must contain certain claims, and they must satisfy certain rules to be considered valid.

In contrast, OpenID Connect is pretty lax about access tokens: They can be JWTs, but they don’t have to. Many identity providers (including Google) use opaque JWTs, and that’s perfectly fine as far as OpenID Connect is concerned.

This lax-ness is a bit of a problem for workload identity federation when it receives tokens issued by external identity providers and needs to validate them. For ID tokens, it can follow the rules defined in the specification. But how is it supposed to validate access tokens?

As it turns out, workload identity federation simply applies the same rules: Whether we pass an ID token, access token, or any other kind of JWT to workload identity federation – in all cases, workload identity federation will follow (a slightly simplified set of) the OpenID connect rules to validate the token.

AD FS access tokens

AD FS access tokens are JWTs, so that’s a good start. But how similar are they to ID Tokens? Let’s take a look.

Here’s an ID token:

{
  "typ": "JWT",
  "alg": "RS256",
  "x5t": "zxmfhQrUJynLMHh3Q0loFA5pSW0",
  "kid": "zxmfhQrUJynLMHh3Q0loFA5pSW0"
}.{
  "aud": "48b87db5-7bf1-4c9d-8464-4d149e75270e",
  "iss": "https://login.example.net/adfs",
  "iat": 1643959688,
  "nbf": 1643959688,
  "exp": 1643963288,
  "auth_time": 1643959687,
  "sub": "MBKAaGfXod0u6GOmSnFUmk9nW6wsPWxb70GF8+Z4jdE=",
  "upn": "[email protected]",
  "unique_name": "EXAMPLE\\bob",
  "sid": "S-1-5-21-2588715005-111030-563750101-1109",
  "apptype": "Public",
  "appid": "48b87db5-7bf1-4c9d-8464-4d149e75270e",
  "authmethod": "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
  "ver": "1.0",
  "scp": "openid"
}.[Signature]

And here’s an access token:

{
  "typ": "JWT",
  "alg": "RS256",
  "x5t": "zxmfhQrUJynLMHh3Q0loFA5pSW0",
  "kid": "zxmfhQrUJynLMHh3Q0loFA5pSW0"
}.{
  "aud": "microsoft:identityserver:48b87db5-7bf1-4c9d-8464-4d149e75270e",
  "iss": "https://login.example.net/adfs/services/trust",
  "iat": 1643959688,
  "nbf": 1643959688,
  "exp": 1643963288,
  "apptype": "Public",
  "appid": "48b87db5-7bf1-4c9d-8464-4d149e75270e",
  "authmethod": "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
  "auth_time": "2022-02-04T07:28:07.359Z",
  "ver": "1.0",
  "scp": "openid"
}.[Signature]

There are obviously a number of differences, but one strikes out: the two tokens use a different issuer (iss):

  • The ID Token uses https://login.example.net/adfs as issuer. In compliance with the OpenID Connect Discovery specification, we can append /.well-known/openid-configuration to that value and get the URL of the OIDC discovery document, which points us to the JWKS.
  • The access token uses https://login.example.net/adfs/services/trust as issuer, and trying to append /.well-known/openid-configuration to that URL gets us nowhere.

This explains why workload identity federation failed to accept AD FS access tokens: It simply didn’t recognize them as coming from a trusted issuer.

There was a workaround for this issue: The URL https://login.example.net/adfs/services/trust is the federation service identifier, and this identifier can be modified in the AD FS settings. But it’s a global setting that affects all clients, so this workaround wasn’t great.

Luckily, this workaround isn’t necessary anymore. Workload identity federation now implements the AD FS-specific rules to validate access tokens, so that both ID tokens and access tokens can be used for authentication.

Updated documentation

I’ve updated the workload identity federation documentation to cover AD FS:

The documentation now also contains some details on how to combine workload identity federation with Integrated Windows Authentication (IWA), a topic we covered in a previous blog post.

Any opinions expressed on this blog are Johannes' own. Refer to the respective vendor’s product documentation for authoritative information.
« Back to home