Skip to content

Azure PKCE Authentication Issue with Cached Refresh Token #1195

@wroujoulah

Description

@wroujoulah

Describe the issue

When using kubelogin with Azure IDP and PKCE authentication, there's an inconsistency in the token exchange behavior between initial authentication and subsequent attempts using cached refresh tokens. The initial authentication works as expected, but subsequent attempts fail due to missing client_id in the token exchange request body.

To reproduce

  1. Create an Azure application with Mobile and desktop applications configuration:

    • Enable "Allow public client flows"
  2. Initial authentication (works):

    kubectl oidc_login get-token \
      --oidc-issuer-url=https://sts.windows.net/<tenant id>/ \
      --oidc-client-id=<client id> \
      --oidc-use-pkce \
      --force-refresh
  3. Subsequent authentication (fails):
    Run the exact same command again. This time it will fail with the error:

    error: get-token: authentication error: authcode-browser error: authentication error: authorization code flow error: oauth2 error: could not exchange the code and token: oauth2: "invalid_request" "AADSTS900144: The request body must contain the following parameter: 'client_id'. Trace ID: [MASKED] Correlation ID: [MASKED] Timestamp: 2024-11-29 07:25:10Z" "https://login.windows.net/error?code=900144"
    

Debug Logs

Working Scenario (First Authentication)

First attempt (fails but triggers retry):

I1129 08:20:55.206480 1779364 oauth2cli.go:156] oauth2cli: exchanging the code and token
I1129 08:20:55.207179 1779364 transport.go:30] POST /[MASKED]/oauth2/token HTTP/1.1
Host: login.windows.net
User-Agent: Go-http-client/1.1
Content-Length: 997
Authorization: Basic [MASKED]
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip

code=[MASKED]&code_verifier=[MASKED]&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A8000
I1129 08:20:55.491795 1779364 transport.go:40] HTTP/1.1 400 Bad Request

{"error":"invalid_request","error_description":"AADSTS900144: The request body must contain the following parameter: 'client_id'. Trace ID: [MASKED] Correlation ID: [MASKED] Timestamp: 2024-11-29 07:20:55Z","error_codes":[900144],"timestamp":"2024-11-29 07:20:55Z","trace_id":"[MASKED]","correlation_id":"[MASKED]","error_uri":"https://login.windows.net/error?code=900144"}

Second attempt (succeeds with client_id):

I1129 08:20:55.492467 1779364 transport.go:30] POST /[MASKED]/oauth2/token HTTP/1.1
Host: login.windows.net
User-Agent: Go-http-client/1.1
Content-Length: 1044
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip

client_id=[MASKED]&code=[MASKED]&code_verifier=[MASKED]&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A8000
I1129 08:20:55.735417 1779364 transport.go:40] HTTP/1.1 200 OK
Failing Scenario (Subsequent Authentication with Refresh Token)

Single attempt (fails with no retry):

I1129 08:23:17.783488 1780146 oauth2cli.go:156] oauth2cli: exchanging the code and token
I1129 08:23:17.783792 1780146 transport.go:30] POST /[MASKED]/oauth2/token HTTP/1.1
Host: login.windows.net
User-Agent: Go-http-client/1.1
Content-Length: 997
Authorization: Basic [MASKED]
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip

code=[MASKED]&code_verifier=[MASKED]&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A8000
I1129 08:23:17.969705 1780146 transport.go:40] HTTP/1.1 400 Bad Request

{"error":"invalid_request","error_description":"AADSTS900144: The request body must contain the following parameter: 'client_id'. Trace ID: [MASKED] Correlation ID: [MASKED] Timestamp: 2024-11-29 07:23:17Z","error_codes":[900144],"timestamp":"2024-11-29 07:23:17Z","trace_id":"[MASKED]","correlation_id":"[MASKED]","error_uri":"https://login.windows.net/error?code=900144"}
I1129 08:23:17.969887 1780146 get_token.go:74] releasing the lock of token cache
error: get-token: authentication error: authcode-browser error: authentication error: authorization code flow error: oauth2 error: could not exchange the code and token: oauth2: "invalid_request" "AADSTS900144: The request body must contain the following parameter: 'client_id'. Trace ID: [MASKED] Correlation ID: [MASKED] Timestamp: 2024-11-29 07:23:17Z" "https://login.windows.net/error?code=900144"
I1129 08:23:17.969946 1780146 cmd.go:76] stacktrace: get-token: authentication error: authcode-browser error: authentication error: authorization code flow error: oauth2 error: could not exchange the code and token: oauth2: "invalid_request" "AADSTS900144: The request body must contain the following parameter: 'client_id'. Trace ID: [MASKED] Correlation ID: [MASKED] Timestamp: 2024-11-29 07:23:17Z" "https://login.windows.net/error?code=900144"

Technical Details

During the first authentication:

  1. The initial token exchange request fails due to missing client_id
  2. A second attempt is made with client_id included in the request body
  3. The authentication succeeds

During subsequent authentications with cached refresh token:

  1. The token exchange request fails due to missing client_id
  2. No second attempt is made
  3. The authentication fails

Note: The refresh token path doesn't work with Azure because Azure doesn't reply with a new id_token during refresh. As a result, kubelogin continues with AuthCodeBrowserOption.

Your environment

  • OS: Ubuntu 20.04.4 LTS
  • kubelogin version: v1.31.0
  • kubectl version: v1.24.17
  • OpenID Connect provider: Azure

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions