I just generated a new Client Secret.  Why can’t I test it?

I was recently engaged in a long running critical case for a customer that exposed some opportunities for further discussion on SharePoint Add-In Authentication.

Here is the scenario: Your organization leverages a Provider Hosted SharePoint Add-in, whose secret is close to expiring.  Following the documented process for Generating a New Client Secret you create a new client secret.  Hoping to confirm the new secret, you modify the Provider Host Web Application Properties to only use the new secret. When you attempt to use your Add-in, it fails.

Understanding the Add-in Authentication Flow

For the following few paragraphs, it will be helpful to review the documentation on The Context Token OAuth flow for SharePoint Add-Ins.  The important take away is the OAuth flow, which is as follows:

  1. User requests the app by clicking on the link in SharePoint.
  2. SharePoint will request a token from Azure.
  3. Azure will sign the token using the oldest valid client secret associated with the ClientID of the App
  4. Azure will pass that token to SPO, which then passes it to the Client.
  5. The client will present the token to the Provider Hosted Web App, which uses the stored Client Secret(s) to validate the token.
  6. If the Provider Hosted Web App doesn’t have the secret that was used to sign the token, it will fail.

The interesting thing to note here is #3.  Because it uses the oldest eligible token, the Provider Hosted Web Application must know about the expiring secret in order to continue working normally.

In order to verify that the client secret is updated, you can query Azure Active Directory using the following code:

 Connect-MSOLService
$clientId = 'client id of the add-in'
Get-MsolServicePrincipalCredential -AppPrincipalId $clientid -ReturnKeyValues $true | Where-Object { ($_.Type -ne "Other") -and ($_.Type -ne "Assymetric") }

If you then see 3 entries with an expiration set to a year (or 3, if you decided to create a new secret 3 years in the future) then you have confirmed that the secret is now valid and can update your Provider Host Web Application Properties.

Forcing a cutover

Once you have verified your new secret above, you can safely wait for the current secret to expire and the transition to the new secret should be seamless. If your organization wants to force a cutover, say during a change window, then you can delete the expiring secrets using the following code.

 Connect-MSOLService
$clientId = 'client id of the add-in'
$secrets = Get-MsolServicePrincipalCredential -AppPrincipalId $clientid -ReturnKeyValues $true | Where-Object { ($_.Type -ne "Other") -and ($_.Type -ne "Assymetric") }
$secrets

Use the output of the $secrets command to identify the date/time of the expiring secret.  Then use the following code:

 $DeleteTheseSecrets = $Secrets | Where-Object { $_.EndDate -like ‘end date of expiring secret’ }
$DeleteTheseSecrets | ForEach-Object {Remove-MSOLServicePrincipalCredential $_.KeyId}

Then remove the old secret from the Provider Host Web Application Properties, and test your App.  Things should smoothly transition to use the new Client Secret.

NOTE: There is no technical reason to engage in a forced cutover. With both client secrets in the Provider Host Web Application Properties, there should be no real need for you to do this.  These steps are provided as a courtesy to customers with strict Change-Control Compliance needs.