to do it. In case someone needs to do it later, here's the code in Java:
// credsStream is the InputStream for the json private key for the service account
ServiceAccountCredentials serviceAccount = ServiceAccountCredentials.fromStream(credsStream);
JwtBuilder jwts = Jwts.builder();
// set header
Map<String, Object> header = new HashMap<>();
header.put("type", "JWT");
header.put("alg", "RS256");
jwts.setHeader(header);
// set claims
Map<String, Object> claims = new HashMap<>();
claims.put("target_audience", "https://echo-api.endpoints.<YOUR_PROJECT_ID>.cloud.goog");
claims.put("exp", System.currentTimeMillis() / 1000 + 3600);
claims.put("iat", System.currentTimeMillis() / 1000);
claims.put("iss", "<SERVICE_ACCOUNT_EMAIL>");
claims.put("aud", "https://www.googleapis.com/oauth2/v4/token");
jwts.addClaims(claims);
// sign with key
jwts.signWith(SignatureAlgorithm.RS256, serviceAccount.getPrivateKey());
// encode base64
String jwt = jwts.compact();
// get jwt from google for your service account
HttpPost httpPost = new HttpPost("https://www.googleapis.com/oauth2/v4/token");
ArrayList<NameValuePair> postParameters = new ArrayList<>();
postParameters.add(new BasicNameValuePair("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"));
// add param for the jwt you got by signing with your private key
postParameters.add(new BasicNameValuePair("assertion", jwt));
CloseableHttpClient httpclient = HttpClients.createDefault();
httpPost.setEntity(new UrlEncodedFormEntity(postParameters, "UTF-8"));
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
HttpResponse response = httpclient.execute(httpPost);
// response.getEntity() will now contain the json with an id_token containing the jwt which you can now use to authenticate with your cloud endpoints.