Mint Okta id_token

A human runs kubectl with no cluster credential on disk. The kubelogin plugin opens a browser, the human signs in to Okta with MFA, and Okta signs an id_token: the only credential kubectl will ever present.

Call sequence

human browser kubectl kubelogin plugin okta dev-12345678.okta.com kube-apiserver k3s-control:6443 1 GET /authorize 2 sign in · MFA 3 302 → ?code 4 POST /token 5 id_token
  • kubelogin starts a loopback server on :8000 and opens this URL in the browser
  • client_id and scope become the token's aud and groups
  • in the browser: the human signs in to Okta with password + MFA (google_otp)
  • Okta records the methods used in the token's amr claim
  • kubelogin never sees these credentials
  • Okta redirects the browser to kubelogin's loopback with a short-lived code, not the token
  • the verifier proves kubelogin started the flow: no client secret anywhere
  • the signed assertion kubectl will present to the kube-apiserver
  • the JWT payload (purple) is shortened here for brevity; the header and signature are complete
request browser
open 'https://dev-12345678.okta.com/oauth2/v1/authorize?client_id=0oa8q2lmv3RtYwHcK5d7&response_type=code&scope=openid%20email%20groups&redirect_uri=http%3A%2F%2Flocalhost%3A8000&code_challenge=HemH84pciomc4QcRJ_mq7zcXwA4AYCIclWSpfvB0zwo&code_challenge_method=S256'
recorded in the id_token
{
  "amr": ["pwd", "mfa", "google_otp"]
}
response 302 Found
Location: http://localhost:8000/?code=qfP3aL9xKwYm7TnCvB2u
request POST
curl -X POST https://dev-12345678.okta.com/oauth2/v1/token \
    -H 'Content-Type: application/x-www-form-urlencoded' \
    -d grant_type=authorization_code \
    -d client_id=0oa8q2lmv3RtYwHcK5d7 \
    -d code=qfP3aL9xKwYm7TnCvB2u \
    -d code_verifier=Mh4kVp9XqTcW2eYbA7gRzL0sFnJuD3oKxNiC8wEmS5d \
    -d redirect_uri=http://localhost:8000
response 200 OK
{
  "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ing5S3FMbUE0dVZyUDBlVDJzQm42Q3dEeUVmR2hKaUtsTW5PcFFyU3RVdlciLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2Rldi0xMjM0NTY3OC5va3RhLmNvbSIsImF1ZCI6IjBvYThxMmxtdjNSdFl3SGNLNWQ3Iiwic3ViIjoiMDB1NWZqOXF4MlRuV2JWckE1ZDciLCJlbWFpbCI6ImxhYi1hZG1pbkBhdXRobGFiLmFwcCIsImdyb3VwcyI6WyJhcHAtazhzLWFkbWlucyJdLCJhbXIiOlsi….anonymized-signature-not-valid-for-cryptographic-use",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "openid email groups"
}
origin · what mints this
# ~/.kube/config — user entry
users:
  - name: okta
    user:
      exec:
        command: kubectl
        args:
          - oidc-login
          - get-token
          - --oidc-issuer-url=https://dev-12345678.okta.com
          - --oidc-client-id=0oa8q2lmv3RtYwHcK5d7
          - --oidc-extra-scope=email,groups   # without groups: thin token

the client_id and scopes you request become the token's aud and groups

alg
RS256
kid
x9KqLmA4uVrP0eT2sBn6CwDyEfGhJiKlMnOpQrStUvW
typ
JWT
Claim Value
iss
https://dev-12345678.okta.com
aud
0oa8q2lmv3RtYwHcK5d7
sub
00u5fj9qx2TnWbVrA5d7
email
lab-admin@authlab.app
groups
["app-k8s-admins"]
amr
["pwd","mfa","google_otp"]
iat
1778600000
exp
1778603600
jti
ID.bT4mWx9KqLpHcAe2sFnVuD7gYiR0oZ3NhCkM
eyJhbGciOiJSUzI1NiIsImtpZCI6Ing5S3FMbUE0dVZyUDBlVDJzQm42Q3dEeUVmR2hKaUtsTW5PcFFyU3RVdlciLCJ0eXAiOiJKV1QifQeyJpc3MiOiJodHRwczovL2Rldi0xMjM0NTY3OC5va3RhLmNvbSIsImF1ZCI6IjBvYThxMmxtdjNSdFl3SGNLNWQ3Iiwic3ViIjoiMDB1NWZqOXF4MlRuV2JWckE1ZDciLCJlbWFpbCI6ImxhYi1hZG1pbkBhdXRobGFiLmFwcCIsImdyb3VwcyI6WyJhcHAtazhzLWFkbWlucyJdLCJhbXIiOlsicHdkIiwibWZhIiwiZ29vZ2xlX290cCJdLCJpYXQiOjE3Nzg2MDAwMDAsImV4cCI6MTc3ODYwMzYwMCwianRpIjoiSUQuYlQ0bVd4OUtxTHBIY0FlMnNGblZ1RDdnWWlSMG9aM05oQ2tNIn0anonymized-signature-not-valid-for-cryptographic-use