Your app worked yesterday, and today every token request comes back with HTTP 401 and AADSTS7000215. Nothing changed in the code, so what broke?
Almost always it’s the credential itself: the app is sending a string that doesn’t match any client secret on its app registration.
Quick answer: AADSTS7000215 invalid client secret provided means Microsoft Entra ID rejected the client_secret your app sent. Copy the secret’s Value, not its Secret ID. If you no longer have the Value, open App registrations > your app > Certificates & secrets > Client secrets > New client secret, copy the new Value right away, and update every place the app reads it from.
In this tutorial, we’ll reproduce the error with a real token request, walk through each cause, fix it in the Microsoft Entra admin center, and explain when to use a certificate.
What AADSTS7000215 Means
AADSTS7000215 comes from the token endpoint in the OAuth 2.0 client credentials flow, the app-only sign-in used by scripts and back-end services. Entra ID compares the secret the app sends with the ones stored on its app registration.
We sent a token request for an existing app in our tenant with a deliberately wrong secret. Entra ID returned this JSON (IDs replaced):
{
"error": "invalid_client",
"error_description": "AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app '<client-id>'. Trace ID: <guid> Correlation ID: <guid> Timestamp: 2026-10-24 09:00:06Z",
"error_codes": [ 7000215 ],
"timestamp": "2026-10-24 09:00:06Z",
"trace_id": "<guid>",
"correlation_id": "<guid>",
"error_uri": "https://login.microsoftonline.com/error?code=7000215"
}
It’s HTTP 401 with invalid_client, and the message names the app ID so you can confirm the registration. The same codes apply to tokens for the SharePoint REST API.
What You Need Before You Start
- Owner or Application Administrator access to the app registration in the Microsoft Entra admin center.
- The client ID and tenant ID your code uses.
- Access to where the app reads its secret (environment variable,
appsettings.json, pipeline, or Key Vault). - PowerShell 7 for the test scripts below. If you also connect with PnP PowerShell, install or update PnP PowerShell first.
Step 1: Reproduce the Error With a Direct Token Request
Before touching the portal, test the secret outside the app, without the SDK or app configuration in the way. Our script reads the IDs and secret from environment variables:
# Client credentials token request (app-only)
$tenantId = $env:SPG_TENANT_ID # Directory (tenant) ID
$clientId = $env:SPG_CLIENT_ID # Application (client) ID
$secret = $env:SPG_CLIENT_SECRET # the secret VALUE, never the Secret ID
$body = @{
client_id = $clientId
client_secret = $secret
scope = "https://graph.microsoft.com/.default"
grant_type = "client_credentials"
}
try {
$token = Invoke-RestMethod -Method Post `
-Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" `
-ContentType "application/x-www-form-urlencoded" -Body $body
"Token received, expires in $($token.expires_in) seconds"
}
catch {
$err = $_.ErrorDetails.Message | ConvertFrom-Json
"HTTP status : $([int]$_.Exception.Response.StatusCode)"
"error : $($err.error)"
"error_codes : $($err.error_codes)"
""
($err.error_description -split ' Trace ID')[0] -split '(?<=\.|ID,) '
}
With the wrong secret, it printed the status, the error code, and Microsoft’s hint:
HTTP status : 401
error : invalid_client
error_codes : 7000215
AADSTS7000215: Invalid client secret provided.
Ensure the secret being sent in the request is the client secret value, not the client secret ID,
for a secret added to app '<client-id>'.

If the script gets a token with your app’s values, the problem is the app’s configuration; if not, the secret is wrong. We use the same pattern to connect to SharePoint Online using PowerShell.
Step 2: Confirm the Client ID and Tenant
Open the Microsoft Entra admin center and go to Entra ID > App registrations > All applications. Select the app and compare the Application (client) ID and Directory (tenant) ID on its Overview page with the values in your code.

A secret belongs to one app registration, so app A’s client ID with app B’s secret gives AADSTS7000215. A wrong tenant usually shows a different code, AADSTS700016 (app not found) or AADSTS90002 (tenant not found).
Don’t confuse the Application (client) ID with the Object ID, either. If the token works but a call later fails with a resource error, see our fix for AADSTS650057 resource not listed.
Step 3: Check the Secret Value, Not the Secret ID
Open Certificates & secrets > Client secrets. Each secret has a Value and a Secret ID; the Secret ID is a GUID label, never the password.

The Value is shown only once, right after you create the secret; after that the portal masks it, as the tooltip says. A copied Secret ID or masked Value can’t be turned back into the real one.
This check flags common copy mistakes and tests each value against the real endpoint:
# Check a client secret before you blame Entra ID
function Test-ClientSecret([string]$Secret) {
$issues = @()
if ($Secret -match '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$') { $issues += "looks like a Secret ID (GUID), not the Value" }
if ($Secret -ne $Secret.Trim()) { $issues += "has leading or trailing whitespace" }
if ($Secret -match '^".*"$') { $issues += "is wrapped in quotes" }
$body = @{ client_id = $env:SPG_CLIENT_ID; client_secret = $Secret
scope = "https://graph.microsoft.com/.default"; grant_type = "client_credentials" }
try {
Invoke-RestMethod -Method Post -Body $body `
-Uri "https://login.microsoftonline.com/$($env:SPG_TENANT_ID)/oauth2/v2.0/token" | Out-Null
$result = "token OK"
} catch {
$result = "AADSTS" + ($_.ErrorDetails.Message | ConvertFrom-Json).error_codes[0]
}
[pscustomobject]@{ Checked = "'$Secret'"; Result = $result; Hint = ($issues -join "; ") }
}
"3f2a9c51-8d4e-4b7a-9f61-2c8e5d7b1a90", # what you get from the Secret ID column
"Abc8Q~exampleValue.copied-with-space ", # a value pasted with a trailing space
'"Abc8Q~exampleValue.copied-in-quotes"' | # a value pasted with its quotes
ForEach-Object { Test-ClientSecret $_ } | Format-Table -AutoSize -Wrap

All three returned AADSTS7000215, and the Hint column says why. Spaces and quotes usually sneak in when you copy from chat, CSV, or JSON.
Step 4: Create a New Client Secret and Copy the Value
When the Value is lost or the secret expired, create a new one. Keep the old secret until the app is switched over.
- In Certificates & secrets, open the Client secrets tab and select New client secret.
- Enter a description that tells you where the secret is used, such as SPGuides user sync – 10/24/2026.
- Pick an Expires value. The default is Recommended: 180 days (6 months), and the longest option is 730 days (24 months).
- Select Add, then copy the Value column immediately and store it in your secret store.

Secrets are limited to 24 months, and Microsoft recommends less than 12. We selected Cancel after this screenshot, so no secret was created.
Then update every copy of the old value (app settings, Key Vault, pipelines, connectors) and restart the service. Our PnP PowerShell scripts for SharePoint developers read credentials from one place for this reason.
Step 5: URL-Encode the Secret in Raw HTTP Calls
Microsoft’s docs say the client secret must be URL-encoded. Invoke-RestMethod with a hashtable and MSAL do it for you; hand-built bodies don’t, so a + or & in the secret changes what Entra ID receives.
With curl, let --data-urlencode do the encoding instead of pasting the secret into a -d string:
curl -X POST "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token" \
--data-urlencode "client_id=<client-id>" \
--data-urlencode "client_secret=$SPG_CLIENT_SECRET" \
--data-urlencode "scope=https://graph.microsoft.com/.default" \
--data-urlencode "grant_type=client_credentials"
The same goes for an HTTP action in Power Automate. Our guide to SharePoint REST API queries with $select and $filter covers encoding in query strings.
Fix AADSTS7000215 in a C# App With MSAL
We first hit this error in a C# Windows Forms tool that read user names from Microsoft Graph. With MSAL.NET, a wrong secret surfaces as an MsalServiceException containing AADSTS7000215:
using Microsoft.Identity.Client;
string tenantId = "<tenant-id>";
string clientId = "<client-id>";
// Read the secret VALUE from configuration or Azure Key Vault - never hard-code it
string clientSecret = Environment.GetEnvironmentVariable("SPG_CLIENT_SECRET")?.Trim();
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri($"https://login.microsoftonline.com/{tenantId}"))
.Build();
try
{
AuthenticationResult result = await app
.AcquireTokenForClient(new[] { "https://graph.microsoft.com/.default" })
.ExecuteAsync();
Console.WriteLine($"Token expires on {result.ExpiresOn:MM/dd/yyyy hh:mm tt}");
}
catch (MsalServiceException ex) when (ex.Message.Contains("AADSTS7000215"))
{
Console.WriteLine("Wrong client secret: paste the secret Value, not the Secret ID.");
}
The Trim() guards against a trailing newline. From SharePoint Framework you don’t need a secret at all; see how to call Microsoft Graph API in SPFx web parts.
Microsoft also says never to ship the credential in a widely distributed native app. A WinForms app on users’ PCs should sign users in as a public client with delegated permissions instead.
AADSTS7000215 Cheat Sheet: Related Error Codes
These codes look alike but need different fixes (from Microsoft’s error code reference):
| Error | What Entra ID is telling you | Fix |
|---|---|---|
| AADSTS7000215 | The secret doesn’t match any secret on this app. | Send the Value, not the Secret ID; create a new secret if the Value is lost. |
| AADSTS7000222 | The secret has expired. | Create a new secret (or a certificate) and update the app. |
| AADSTS7000218 | No client_secret or client_assertion in the request. | Add the credential, or enable public client flows for a desktop or device code sign-in. |
| AADSTS700016 | The app wasn’t found in that tenant. | Check the client ID and the tenant in the token URL. |
| AADSTS90002 | The tenant name or ID wasn’t found. | Fix the tenant ID or domain in the authority URL. |
| AADSTS700025 | The app is a public client, so it can’t send a secret. | Drop the secret, or use a confidential client app registration. |
For any code, https://login.microsoftonline.com/error?code=7000215 shows Microsoft’s current wording; swap in your number. Interactive PnP sign-ins throw a different set; our post on AADSTS500113 no reply address is registered covers the redirect URI one.
Does a Client Secret Work for SharePoint App-Only Access?
Not for SharePoint itself. Microsoft’s docs say SharePoint REST and CSOM app-only access through Entra ID requires a certificate; anything else ends in Access Denied, even after AADSTS7000215 is fixed.
Upload the certificate under Certificates & secrets > Certificates > Upload certificate (a .cer, .pem, or .crt file), and keep the private key on the machine that runs the code:

In C#, swap WithClientSecret for WithCertificate and use your SharePoint host as the scope. This token works with CSOM in SharePoint Online and REST:
X509Certificate2 certificate = new X509Certificate2(@"C:\certs\SPGuidesApp.pfx", pfxPassword);
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithCertificate(certificate)
.WithAuthority(new Uri($"https://login.microsoftonline.com/{tenantId}"))
.Build();
// App-only token for SharePoint: the scope is the SharePoint host + /.default
AuthenticationResult result = await app
.AcquireTokenForClient(new[] { "https://spguides.sharepoint.com/.default" })
.ExecuteAsync();
In PnP PowerShell, connect with the same app and the certificate’s thumbprint:
Connect-PnPOnline -Url "https://spguides.sharepoint.com/sites/SPGuides" `
-ClientId "<client-id>" -Tenant "spguides.onmicrosoft.com" `
-Thumbprint "<certificate thumbprint>"
Get-PnPWeb | Select-Object Title, Url
Old Add-in secrets from appregnew.aspx used Azure ACS, fully retired for SharePoint Online on April 2, 2026; move those apps to Entra ID with a certificate.
Common Mistakes to Avoid
- Copying the Secret ID. It’s a GUID and it sits right next to the Value. Our check script flags it.
- Rotating the secret in one place only. A staging slot or pipeline with the old value keeps failing.
- Mixing apps or tenants. A client ID from one registration with a secret from another always fails.
- Treating an expired secret as AADSTS7000215. Expired secrets return AADSTS7000222, so check the Expires column first when that code appears.
After the fix, run a simple read to prove the whole chain works, such as SharePoint PowerShell commands from our cheat sheet.
Next Steps
Set a reminder for the secret’s expiry date, or move production apps to a certificate. Then our guide to SharePoint REST API CRUD operations is a good next test of the permissions your app actually has.
We’d also keep these app and PowerShell guides handy:
Frequently Asked Questions
What does AADSTS7000215 invalid client secret provided mean?
Microsoft Entra ID received a client_secret that doesn’t match any secret on the app registration. The usual cause is sending the Secret ID instead of the Value. Microsoft’s Entra authentication error code reference lists it with the related codes.
Where do I find the client secret value in Microsoft Entra ID?
Only on the Certificates & secrets page right after you create the secret. After that it’s masked and can’t be read again, so create a new secret and copy its Value immediately, as Microsoft’s guide to adding and managing app credentials describes.
Does an expired client secret cause AADSTS7000215?
No. An expired secret returns AADSTS7000222, which says the provided client secret keys are expired. AADSTS7000215 means the value itself is wrong.
How long can a client secret last?
Up to 24 months. The admin center defaults to 180 days, and Microsoft recommends less than 12 months, or a certificate for production apps.
Can I use a client secret for SharePoint Online app-only access?
You can get a token, but SharePoint rejects it for REST and CSOM calls. SharePoint app-only access through Entra ID requires a certificate.

Hey! I’m Bijay Kumar, founder of SPGuides.com and a Microsoft Business Applications MVP (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and training videos. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.