Skip to content

Previous session data leaks into new user's session when using same browser instance #127

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
theolint opened this issue May 20, 2025 · 0 comments · May be fixed by #128
Open

Previous session data leaks into new user's session when using same browser instance #127

theolint opened this issue May 20, 2025 · 0 comments · May be fixed by #128

Comments

@theolint
Copy link

Description

Session data from one user's session will leak into a new user's session if:

  1. The new user is logging in from the same browser as the previous user and has not cleared cookies
  2. The OIDC session times out and the user does not logout with an explicit logout from the Nuxt app
  3. The previous session contains extracted optionalClaims that are either a complex type or are not present on the new user's ID token

A somewhat related issue is that optionalClaims which are complex types containing arrays "grow" each time the session is refreshed.

I have fixed both problems in my fork here and will open a PR: https://github.com/theolint/nuxt-oidc-auth

Steps to Reproduce

I reproduced this issue with Keycloak on commit bc044d9, with Keycloak configured to add roles to the ID token (which is non-standard)

Keycloak Instance Config

  • Realm master
  • Created client playground with client authentication
  • Created client roles admin-role and user-role
  • Created realm users pgadmin with playground role admin-role and pguser with playground role user-role
  • Client scopes → Edit roles scope
    • Mappers → Edit client roles mapper
      • Enable “Add to ID token”

Verify that pgadmin gets the following claim in the ID token:

"resource_access": {
  "playground": {
    "roles": [
      "admin-role"
    ]
  },

and that pguser gets a similar claim with user-role instead

Playground Config

Configure keyclock provider in nuxt-oidc-auth playground. Set optionalClaims to pull in resource_access claim.

keycloak: {
  audience: 'account',
  baseUrl: 'http://localhost:8001/realms/master',
  clientId: 'playground',
  clientSecret: 'nmNRIfDz8hQujTOHD079IaocaLmTbfKm',
  redirectUri: 'http://localhost:3000/auth/keycloak/callback',
  userNameClaim: 'preferred_username',
  logoutRedirectUri: 'http://localhost:3000',
  optionalClaims: ['resource_access'],
  // For testing Single sign-out
  sessionConfiguration: {
    singleSignOut: true,
  },
},

Testing

Open playground app and login with Keycloak as pgadmin. Observe that claims contains admin-role.

On my first test, it actually included admin-role twice:

{ "resource_access": { "playground": { "roles": [ "admin-role", "admin-role" ] }, "account": { "roles": [ "manage-account", "manage-account-links", "view-profile", "manage-account", "manage-account-links", "view-profile" ] } }, "status": "Fetch" }

Which is not what is in the ID token:

eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ3S1ZCWnBwYXRScnQxSkVGaVBOaXFsdllad1lFb1ZWT3hRR2c0TGt6UGVZIn0.eyJleHAiOjE3NDc2ODEzNTYsImlhdCI6MTc0NzY4MTI5NiwiYXV0aF90aW1lIjoxNzQ3NjgxMjk2LCJqdGkiOiJjOWZiODk2ZS0zNTRjLTQwNTMtOGVkYi04YWM3MmEyZTM1ZDAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwMDEvcmVhbG1zL21hc3RlciIsImF1ZCI6InBsYXlncm91bmQiLCJzdWIiOiI4MGI5MWEzMS04YzkzLTRhMWEtOWEwZC1jODdiMjU5ZGE2NDMiLCJ0eXAiOiJJRCIsImF6cCI6InBsYXlncm91bmQiLCJzaWQiOiI3YmMwY2ZmYS05YzZmLTRkODMtYjZjZi04MDY3ZTkwMjUyM2IiLCJhdF9oYXNoIjoiaDl2UkJBMlV4OTJVd0lVUnh6Vm9LQSIsImFjciI6IjEiLCJyZXNvdXJjZV9hY2Nlc3MiOnsicGxheWdyb3VuZCI6eyJyb2xlcyI6WyJhZG1pbi1yb2xlIl19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiJQbGF5Z3JvdW5kIEFkbWluIiwicHJlZmVycmVkX3VzZXJuYW1lIjoicGdhZG1pbiIsImdpdmVuX25hbWUiOiJQbGF5Z3JvdW5kIiwiZmFtaWx5X25hbWUiOiJBZG1pbiJ9.DwXXLXWEy7m1s5cm2ZDc_7J2GKSvTEaB2QQwJNiibC_O8AVB4fytqrZKAlP6J1DXIFw2nSI8E2VEtt_6doH6j9csft0_ulLjTyGrKgSKolM2iUKg_TWajx61Ob1eAu1seteHAuR5vfZqUmIcVn8g-kWNkNjS1GJqnn_YVXLV7hkFqd4m22snzNhZZSLD7rcscYZtscNwi-6Afb5zA7oL1trn4gnwe8bbb7Tv5hdcnQYmbZahDWxoVk7i31RijzeiHdgH_F6efo1xza2IXGUk1FcwjIzHaf8Huq7ro_pmu30ByWyTPWpCZP3LzJvpQUqsR0cHhkodwgt9cJ5YtKQeBw

Which has a payload part that decodes to:

{
  "exp": 1747681356,
  "iat": 1747681296,
  "auth_time": 1747681296,
  "jti": "c9fb896e-354c-4053-8edb-8ac72a2e35d0",
  "iss": "http://localhost:8001/realms/master",
  "aud": "playground",
  "sub": "80b91a31-8c93-4a1a-9a0d-c87b259da643",
  "typ": "ID",
  "azp": "playground",
  "sid": "7bc0cffa-9c6f-4d83-b6cf-8067e902523b",
  "at_hash": "h9vRBA2Ux92UwIURxzVoKA",
  "acr": "1",
  "resource_access": {
    "playground": {
      "roles": [
        "admin-role"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },
  "email_verified": false,
  "name": "Playground Admin",
  "preferred_username": "pgadmin",
  "given_name": "Playground",
  "family_name": "Admin"
}

Re-Creating Error

Use the Keycloak admin console from a private window to sign-out the user. The bug will occur naturally if the Keycloak session is allowed to time out but this speeds up the test.

Refresh the playground screen until it returns to the login page.

Login again, this time as pguser

Claims now contains pgadmin’s roles as well as pguser’s roles:

{ "resource_access": { "playground": { "roles": [ "user-role", "user-role", "admin-role" ] }, "account": { "roles": [ "manage-account", "manage-account-links", "view-profile", "manage-account", "manage-account-links", "view-profile", "manage-account", "manage-account-links", "view-profile" ] } }, "status": "Fetch" }

The ID token only contains the expected roles:

eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ3S1ZCWnBwYXRScnQxSkVGaVBOaXFsdllad1lFb1ZWT3hRR2c0TGt6UGVZIn0.eyJleHAiOjE3NDc2ODE2MzUsImlhdCI6MTc0NzY4MTU3NSwiYXV0aF90aW1lIjoxNzQ3NjgxNTc1LCJqdGkiOiIxOTlkZDg4MS1jYmVmLTQ5YTgtYWMxMy03MzMxNzgxMDJkNTEiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwMDEvcmVhbG1zL21hc3RlciIsImF1ZCI6InBsYXlncm91bmQiLCJzdWIiOiI2NTA1Y2FjOC0wZWY0LTRkYWMtYjkwMC0zM2U1YWM1NDgzZTciLCJ0eXAiOiJJRCIsImF6cCI6InBsYXlncm91bmQiLCJzaWQiOiI5Mjg2N2E1MC03NDM0LTRhYWQtODIxMS1iNTEzYzdhMWYzMDYiLCJhdF9oYXNoIjoiM1RmY0RURnBMb3g0Q2NDQ3djRDZXUSIsImFjciI6IjEiLCJyZXNvdXJjZV9hY2Nlc3MiOnsicGxheWdyb3VuZCI6eyJyb2xlcyI6WyJ1c2VyLXJvbGUiXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6IlBsYXlncm91bmQgVXNlciIsInByZWZlcnJlZF91c2VybmFtZSI6InBndXNlciIsImdpdmVuX25hbWUiOiJQbGF5Z3JvdW5kIiwiZmFtaWx5X25hbWUiOiJVc2VyIn0.pmayDPdXZNR4iQu3vMSNBdx9yBmnGBpaOccXciGVkpxpAV6qbxAUKRnTK6_oJ5q_PgtBZj2oVEjZOIDbTJVII5gTiAWEvCwO25SlHxRZHeBwghp3qvgGoFYvCMz-5OJmuIcQYYQHYVy8OjCofb_qvfhjuzawcbeMlzBUxg1oVwZuOaPfJ4cHv0050e-8loHa4D58SnUO5ib6PNcP_VPKEy7cnS2zMXhHqFxokqRUl7UzqELvN3nDTzi2uWNBWhUaxjcbtDZ4NP0DFpM9SQ96gsbHVMxGEgA0tRqB06fO3SJweyWKeC3IbXJ_N2QJQwexF5YEeCsiIBzPO8LimW2npg

Above ID token for pguser decoded payload:

{
  "exp": 1747681635,
  "iat": 1747681575,
  "auth_time": 1747681575,
  "jti": "199dd881-cbef-49a8-ac13-733178102d51",
  "iss": "http://localhost:8001/realms/master",
  "aud": "playground",
  "sub": "6505cac8-0ef4-4dac-b900-33e5ac5483e7",
  "typ": "ID",
  "azp": "playground",
  "sid": "92867a50-7434-4aad-8211-b513c7a1f306",
  "at_hash": "3TfcDTFpLox4CcCCwcD6WQ",
  "acr": "1",
  "resource_access": {
    "playground": {
      "roles": [
        "user-role"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },
  "email_verified": false,
  "name": "Playground User",
  "preferred_username": "pguser",
  "given_name": "Playground",
  "family_name": "User"
}

Claims Merging Bug

Refreshing the session repeatedly will keep appending array items nested within a claim that is an object:

{
  "resource_access": {
    "playground": {
      "roles": [
        "user-role",
        "user-role",
        "user-role",
        "user-role",
        "user-role",
        "user-role",
        "user-role",
        "user-role",
        "user-role",
        "user-role",
        "user-role",
        "user-role",
        "user-role"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile",
        "manage-account",
        "manage-account-links",
        "view-profile",
        "manage-account",
        "manage-account-links",
        "view-profile",
        "manage-account",
        "manage-account-links",
        "view-profile",
        "manage-account",
        "manage-account-links",
        "view-profile",
        "manage-account",
        "manage-account-links",
        "view-profile",
        "manage-account",
        "manage-account-links",
        "view-profile",
        "manage-account",
        "manage-account-links",
        "view-profile",
        "manage-account",
        "manage-account-links",
        "view-profile",
        "manage-account",
        "manage-account-links",
        "view-profile",
        "manage-account",
        "manage-account-links",
        "view-profile",
        "manage-account",
        "manage-account-links",
        "view-profile",
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },
  "status": "Refresh"
}

Fix

User sessions should be cleared in the login flow because there may not have been an explicit logout action to do this.

The growing array bug is caused by the use of defu() which I replaced a more explicit copy of UserSession data from the refreshed token into the session.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant