<p><strong>Background</strong></p>
<p>On the Google Kubernetes Engine we've been using Cloud Endpoints, and the Extensible Service Proxy (v2) for service-to-service authentication.</p>
<p>The services authenticate themselves by including the bearer JWT token in the <code>Authorization</code> header of the HTTP requests.</p>
<p>The identity of the services has been maintained with GCP Service Accounts, and during deployment, the Json Service Account key is mounted to the container at a predefined location, and that location is set as the value of the <code>GOOGLE_APPLICATION_CREDENTIALS</code> env var.</p>
<p>The services are implemented in C# with ASP.NET Core, and to generate the actual JWT token, we use the Google Cloud SDK (<a href="https://github.com/googleapis/google-cloud-dotnet" rel="nofollow noreferrer">https://github.com/googleapis/google-cloud-dotnet</a>, and <a href="https://github.com/googleapis/google-api-dotnet-client" rel="nofollow noreferrer">https://github.com/googleapis/google-api-dotnet-client</a>), where we call the following method:</p>
<pre class="lang-cs prettyprint-override"><code>var credentials = GoogleCredential.GetApplicationDefault();
</code></pre>
<p>If the <code>GOOGLE_APPLICATION_CREDENTIALS</code> is correctly set to the path of the Service Account key, then this returns a <code>ServiceAccountCredential</code> object, on which we can call the <code>GetAccessTokenForRequestAsync()</code> method, which returns the actual JWT token.</p>
<pre class="lang-cs prettyprint-override"><code>var jwtToken = await credentials.GetAccessTokenForRequestAsync(&quot;https://other-service.example.com/&quot;);
var authHeader = $&quot;Bearer {jwtToken}&quot;;
</code></pre>
<p>This process has been working correctly without any issues.</p>
<p>The situation is that we are in the process of migrating from using the manually maintained Service Account keys to using <a href="https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity" rel="nofollow noreferrer">Workload Identity</a> instead, and I cannot figure out how to correctly use the Google Cloud SDK to generate the necessary JWT tokens in this case.</p>
<p><strong>The problem</strong></p>
<p>When we enable Workload Identity in the container, and don't mount the Service Account key file, nor set the <code>GOOGLE_APPLICATION_CREDENTIALS</code> env var, then the <code>GoogleCredential.GetApplicationDefault()</code> call returns a <code>ComputeCredential</code> instead of a <code>ServiceAccountCredential</code>.<br />
And if we call the <code>GetAccessTokenForRequestAsync()</code> method, that returns a token which is not in the JWT format.</p>
<p>I checked the implementation, and the token seems to be retrieved from the Metadata server, of which the expected response format seems to be the standard OAuth 2.0 model (represented in <a href="https://github.com/googleapis/google-api-dotnet-client/blob/master/Src/Support/Google.Apis.Auth/OAuth2/Responses/TokenResponse.cs" rel="nofollow noreferrer">this model class</a>):</p>
<pre><code>{
  &quot;access_token&quot;: &quot;foo&quot;,
  &quot;id_token&quot;: &quot;bar&quot;,
  &quot;token_type&quot;: &quot;Bearer&quot;,
  ...
}
</code></pre>
<p>And the <code>GetAccessTokenForRequestAsync()</code> method returns the value of <code>access_token</code>. But as far as I understand, that's not a JWT token, and indeed when I tried using it to authenticate against ESP, it responded with</p>
<pre><code>{
 &quot;code&quot;: 16,
 &quot;message&quot;: &quot;JWT validation failed: Bad JWT format: Invalid JSON in header&quot;,
 ..
}
</code></pre>
<p>As far as I understand, normally the <code>id_token</code> contains the JWT token, which should be accessible via the <code>IdToken</code> property of the <code>TokenResponse</code> object, which is also accessible via the SDK, I tried accessing it like this:</p>
<pre><code>var jwtToken = ((ComputeCredential)creds.UnderlyingCredential).Token.IdToken;
</code></pre>
<p>But this returns <code>null</code>, so apparently the metadata server does not return anything in the <code>id_token</code> field.</p>
<p><strong>Question</strong></p>
<p>What would be the correct way to get the JWT token with the .NET Google Cloud SDK for accessing ESP, when using Workload Identity in GKE?</p>

Mark Vincze
<p>To get an IdToken for the attached service account, you can use <code>GoogleCredential.GetApplicationDefault().GetOidcTokenAsync(...)</code>.</p>
