# SharePoint - Extending app only secret lifetime


Perhaps you need an app principal to be able to access a particular SharePoint site? You could be using the great [SharePoint PnP PowerShell module](https://docs.microsoft.com/en-us/powershell/sharepoint/sharepoint-pnp/sharepoint-pnp-cmdlets?view=sharepoint-ps) and you want to [connect via an AppId and AppSecret](https://docs.microsoft.com/en-us/powershell/module/sharepoint-pnp/connect-pnponline?view=sharepoint-ps).

<!--truncate-->

You've got two choices:

## [Grant access using Azure AD app-only](https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread)

Microsoft's preferred method when using SharePoint Online.

All you have to do is register an Azure AD App Principal and grant the relevant permissions to SharePoint. That can all be done via the Azure AD portal.

The downside of this is that you can't limit permissions to a particular Site. The principal will have access across the whole of your SharePoint tenancy.

## [Grant access using SharePoint App-Only principal](https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azureacs)

This is the older method up setting up app-principals. It allows you to generate a principal with very specific permissions and at different levels:

- **Tenant** \- permissions across whole SharePoint tenancy
- **Site Collection** - permissions at site collection scope
- **Site / Sub Site** - permissions at a site level or even sub-level
- **List** \- permissions at list level for a site/sub-site

As you can see the benefit of this model is that you can assign fine grain permissions that Info-sec will be happier with.

The downside is that by registering the app via the _AppRegNew.aspx_, the secret will have a **default expiry of only 1 year**! Furthermore, from the web interface, you have no way of changing this or even being able to see the expiry date. However, you can view the expiry using PowerShell (see the Extend current secret lifetime section).

**Note** \- This method only works for SharePoint Online.

### Create new Azure AD app registration

The goods news is that you can create an Azure AD app principal with a secret that has a custom expiry date. You can then assign SharePoint permissions using the standard _AppInv.aspx_ page method.

To create the registration, you can use the Azure AD web portal. However, I find it easier and quicker to use PowerShell.

You'll need the Azure AD PowerShell V2 module installed (instructions [here](https://docs.microsoft.com/en-us/powershell/azure/active-directory/install-adv2?view=azureadps-2.0)) and you will need to use an account that has at least the **Cloud Application Administrator** role assigned.

The following code will:

1. **Connect to Azure AD** - replace tenantId with your id.
2. **Create a new Azure AD Application registration** - usually found under App registrations
3. **Register a new Azure AD service principal** - usually found under Enterprise applications
4. **Create a new secret** - with a 49 year expiry from today.

```powershell
Connect-AzureAD -TenantId <tenantId>
$appName = "<appName>"
$appURI = "https://$appName.<tenantId>.onmicrosoft.com"
$appHomePageUrl = "https://localhost"
$appReplyURLs = @($appURI, $appHomePageURL, "https://localhost:1234")

if(!($myApp = Get-AzureADApplication -Filter "DisplayName eq '$($appName)'" -ErrorAction SilentlyContinue))
{
    $myApp = New-AzureADApplication -DisplayName $appName -IdentifierUris $appURI -Homepage $appHomePageUrl -ReplyUrls $appReplyURLs
}

$svcprincipal = New-AzureADServicePrincipal -AppId $myApp.AppId

$startDate = Get-Date
$EndDate = $startDate.AddYears(49)
$aadAppKeyPwd = New-AzureADApplicationPasswordCredential -ObjectId $myApp.ObjectId -CustomKeyIdentifier "Default" -StartDate $startDate -EndDate $endDate
```

You can verify that everything was created successfully by going to:

Azure > Azure Active Directory > App registrations > {appName} > Certificates & Secrets

![app registration secrets](https://cdn.hashnode.com/res/hashnode/image/upload/v1706035665838/e0090b83-bf4f-4fc1-8d1f-55128aaae93f.png)

You should see a secret named **Default** with a long expiry date.

The secret is accessible in the **$aadAppKeyPwd.Value** property. Make sure you save it as it won't be viewable again. You'll also want to record the **$myApp.AppId** value to use later.

### Grant SharePoint access

Now that you have a service principal to work with you need to assign the appropriate SharePoint permission. To do that you need go to the relevant _AppInv.aspx_ page. The page location depends on which permission level/scope you want to assign:

- **Tenant level** - https://{tenant\_name}-**admin**.sharepoint.com/\_layouts/15/appinv.aspx
- **Site collection level** - https://{tenant\_name}.sharepoint.com/**sites/{site\_collection}**/\_layouts/15/appinv.aspx
- **Site/sub-site/list level** - https://{tenant\_name}.sharepoint.com/sites/**{site\_collection}**/**{site}**/\_layouts/15/appinv.aspx

Go to the relevant _AppInv.aspx_ page and under **AppId** enter the value stored in $myApp.AppId and press **Lookup**. The app registration information should then be returned.

![SharePoint app inventory page](https://cdn.hashnode.com/res/hashnode/image/upload/v1706035667023/cb8ed6de-bd11-4c28-8fd7-b6e820d952b2.png)

In the **App's Permission Request XML** textbox you will need to provide the correct XML based on the permission you want to grant. Microsoft have some documentation available [here](https://docs.microsoft.com/en-us/sharepoint/dev/sp-add-ins/add-in-permissions-in-sharepoint) that explains what the available permission scopes are.

For this example, I'm going to grant **full control** at a site level:

<AppPermissionRequests AllowAppOnlyPolicy="true">
  <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web"
   Right="FullControl" />
</AppPermissionRequests>

**Note** \- If you're not sure of the correct XML then have a look at this [cheat sheet](https://medium.com/ng-sp/sharepoint-add-in-permission-xml-cheat-sheet-64b87d8d7600).

Press **Create** to commit your changes. You may be prompted to trust the app, you will need to press **Trust It** to grant the permissions.

![Trust SharePoint app permissions](https://cdn.hashnode.com/res/hashnode/image/upload/v1706035668389/c2271e05-5b62-49c5-8029-d841acd2d2dc.png)

You now have a app registration that won't expire for a long long time!

## Extend current secret lifetime

If you can't create a new app registration or need to update an existing app. You can use a bit of PowerShell to generate a new secret with a custom lifetime.

Connect to Azure AD using the Azure AD V2 PowerShell Module:

```powershell
Connect-AzureAD -TenantId <tenantId>
```

Find the Service Principal that you need to update:

```powershell
$apps = Get-AzureADServicePrincipal -All $true | ? DisplayName -like '\*{appName}\*'
```

Piping out to a table you can see that the test-sp-generated-app is listed:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706035669567/50b78bc6-9916-42fe-9d45-3b01be556f8e.png)

This is the one I created via the _AppRegNew.aspx_ page. I'm just going to store that object in the $app variable to make the rest of the commands easier to write.

Next, we're going to list the existing secrets:

```powershell
Get-AzureADServicePrincipalPasswordCredential -ObjectId $app.ObjectId
```

The auto generated key is displayed and you can see that the end date is 1 year from the start date:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706035670757/df2d895a-9e5c-4430-9d95-d4dd5e7bf271.png)

However, we can't set a new EndDate for an existing secret. Therefore, we have to create a new secret:

```powershell
$startDate = Get-Date
$endDate = $startDate.AddYears(49)
New-AzureADServicePrincipalPasswordCredential -ObjectId $app.ObjectId -CustomKeyIdentifier "Test" -StartDate $startDate -EndDate $endDate
```

A new secret is created and is stored in the **Value** property:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706035671975/9b111231-9a04-4bf1-8f03-c364be1c69c2.png)

If you run the `Get-AzureADServicePrincipalPasswordCredential` again, you should now see two credentials:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706035673271/16f066b5-d24a-414b-a9db-2ee245b7aa3b.png)

To test if the new secret works you can try connecting to the site via PnP cmdlets:

```powershell
Connect-PnPOnline -AppId $app.AppId -AppSecret {value} -Url {url of SharePoint site}

Get-PnpList
```

You should see all the Lists contained in the site:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706035674505/0ec3e2a5-8271-4a13-97ba-3488c74b3142.png)

Success! You now have a new secret that won't expire for a long time.

You should update your code to use the new secret and verify everything is working as expected. Lastly, delete the old credential:

```powershell
Remove-AzureADServicePrincipalPasswordCredential -ObjectId $app.ObjectId -KeyId {old keyId}
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706035675777/d668c4dd-52d5-4133-9578-3be44ffcaa5f.png)

