Add support for dynamic policies

Created on 22 June 2023, about 1 year ago
Updated 23 June 2023, about 1 year ago

Problem/Motivation

The project I am working on has a policy for sign-up/sign-in and password change.
The flow that is problematic is this:
- User logs in on AD B2C (redirect to authorize using hardcoded 'B2C_1A_SignUpSignIn' policy specified in endpoint settings).
- Auth code is returned in redirect URL and tokens are retrieved from token endpoint (again using hardcoded policy in endpoint settings).
- User now wishes to change their password. For this we have a custom policy on AD B2C (I am told this is the only solution in AD B2C), meaning we need to authorize specifying the password change policy (B2C_1A_SelfService_PasswordChange).
- User is redirected to (authorize) AD B2C password change flow and changes their password (I am handling this in custom code).
- User is redirected back to Drupal with auth code and a request to tokens is made.
- At this point the token endpoint is called but the policy specified from the hardcoded endpoint setting is for 'B2C_1A_SignUpSignIn' whereas the auth code we have was granted for the 'B2C_1A_SelfService_PasswordChange' policy, therefore tokens request fails with:
{"error":"invalid_grant","error_description":"AADB2C90088: The provided grant has not been issued for this endpoint. Actual Value : B2C_1A_SignUpSignIn and Expected Value : B2C_1A_SelfService_PasswordChange ...}

Proposed resolution

Rather than hardcoding the policy in the endpoint settings (authorize, tokens), I propose a setting to specify a default policy which is later appended to the endpoints during $client->getEndpoints(). The policy can be overridden by calling code (e.g. when invoking authorize with password change policy from custom code) by setting $_SESSION['openid_connect_policy'] = 'B2C_1A_SelfService_PasswordChange'.
Note that this session var will need to be set and unset in custom code. I am setting it where I invoke the authorize for the password change, and unsetting it in a custom submit handler (openid_connect_login_form) as this form should always use the default policy (B2C_1A_SignUpSignIn).
This allows your application to keep the state of the current flow/policy from which the current tokens were granted (in my case id_token, access_token, refresh_token) during the users AD B2C session. If your application needs to do things like refreshing expired tokens, ending session etc then dynamic policy and keeping state of the current policy is needed, afaik.

I don't believe password change using a custom policy is an extremely unique requirement so perhaps this may help others too.
I am not sure I have gone the right way about this, but for the moment I have patched only openid_connect_windows_aad. Perhaps adding a passwordChange() method to openid_connect module which can be overridden in this module would be better solution.

For now, I have added a new setting 'default_policy', which if specified will enable the dynamic policy behaviour. If the 'default_policy' setting is set, then the policy should not be included in any of the endpoint settings, as it will be appended by a modified $client->getEndpoints() method.

✨ Feature request
Status

Active

Version

1.0

Component

Code

Created by

πŸ‡¬πŸ‡§United Kingdom davewilly

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.69.0 2024