Okta SAML 2.0 app setup: fix NameID, audience, and signed assertions
This guide is for developers wiring an SP to Okta over SAML 2.0 and hitting the usual failures: bad NameID format, audience mismatch, or signature validation errors. You’ll leave with an Okta app configured with literal values, a matching SP config, and concrete verification steps that prove the login works end to end.
TL;DR — For most broken Okta SAML integrations, the root cause is one of three mismatches: the SP expects a different NameID format than Okta sends, the SP entity ID does not exactly match Okta’s Audience URI, or the SP requires signed assertions while Okta is signing the response only. Set the SP Entity ID and Okta Audience URI to the exact same string, pick the NameID format your SP actually parses, and import Okta’s signing certificate into the SP. Reading time: ~5 min
Goal
When you finish, an Okta SAML 2.0 application can initiate a successful sign-in to your service provider, and your SP will accept the assertion because the NameID format, audience restriction, and signature settings all match exactly.
Prerequisites
- Okta admin access that can create or edit applications in your org
- Your SP’s SAML settings page or config file access
- The SP ACS URL, for example
https://app.example.com/saml/acs - The SP Entity ID / Audience value the SP expects, for example
https://app.example.com/saml/metadata - The NameID format your SP expects, usually one of:
urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddressurn:oasis:names:tc:SAML:1.1:nameid-format:unspecifiedurn:oasis:names:tc:SAML:2.0:nameid-format:persistent
curlavailable locally — check with:
curl --version
opensslavailable locally — check with:
openssl version
- A browser with access to your Okta org and your SP login flow
- Optional but useful: a SAML tracer browser extension to inspect the posted assertion
Steps
Step 1: Collect the exact SP values before touching Okta
Use the literal values from your SP config or metadata. If your SP exposes metadata, fetch it and extract the ACS and entity ID.
curl -fsSL https://app.example.com/saml/metadata | sed -n '1,120p'
Look for XML like this:
<EntityDescriptor entityID="https://app.example.com/saml/metadata">
<SPSSODescriptor>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://app.example.com/saml/acs" index="1"/>
</SPSSODescriptor>
</EntityDescriptor>
What you should see: one exact entityID string and one exact ACS Location URL you can copy into Okta.
Step 2: Create or edit the SAML app in Okta with literal ACS and audience values
In Okta Admin Console, go to Applications → Applications → Create App Integration → SAML 2.0.
Enter these literal fields:
| Okta field | Value |
|---|---|
| Single sign-on URL | https://app.example.com/saml/acs |
| Audience URI (SP Entity ID) | https://app.example.com/saml/metadata |
| Name ID format | EmailAddress or Unspecified or Persistent |
| Application username | Email if using EmailAddress; otherwise the exact user field your SP expects |
If editing an existing app, use Applications → Applications → <your app> → Sign On → Edit and replace the values exactly.
What you should see: the Sign On settings page shows the ACS URL and Audience URI exactly matching your SP values, character-for-character.
Step 3: Set the NameID format to what the SP actually parses
Pick one format and align both sides. Use these common mappings:
- If your SP expects an email in NameID, set Okta
Name ID format = EmailAddressandApplication username = Email - If your SP ignores format and just reads the string, set
Name ID format = Unspecified - If your SP tracks a stable opaque identifier, set
Name ID format = Persistent
In Okta, the menu path is:
Applications → Applications → <your app> → Sign On → Edit
Set:
Name ID format: EmailAddress
Application username: Email
Update application username on: Create and update
What you should see: the preview or saved settings show Name ID format: EmailAddress and the app user assignment resolves to a real email value.
Step 4: Export Okta IdP metadata and signing certificate
From the same app, open the SAML setup instructions or metadata link exposed by Okta for the app, then copy the metadata URL and download it.
curl -fsSL "https://your-okta-domain.example.com/app/<app-path>/sso/saml/metadata" -o okta-idp-metadata.xml
sed -n '1,160p' okta-idp-metadata.xml
Extract the certificate if your SP wants a PEM file instead of metadata:
python3 - <<'PY'
import re
xml=open('okta-idp-metadata.xml').read()
m=re.search(r'<X509Certificate>([^<]+)</X509Certificate>', xml)
cert=m.group(1)
print('-----BEGIN CERTIFICATE-----')
for i in range(0,len(cert),64):
print(cert[i:i+64])
print('-----END CERTIFICATE-----')
PY
What you should see: metadata containing <EntityDescriptor>, <SingleSignOnService>, and <X509Certificate>.
Step 5: Configure your SP to trust Okta and require signed assertions if that is your policy
Use your SP’s SAML config page or file and set the IdP values from Okta metadata. If your SP uses a config file, it will look roughly like this:
{
"saml": {
"idp_metadata_url": "https://your-okta-domain.example.com/app/<app-path>/sso/saml/metadata",
"idp_entity_id": "http://www.okta.com/<id>",
"sso_url": "https://your-okta-domain.example.com/app/<app-path>/sso/saml",
"x509cert": "-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----",
"want_assertions_signed": true,
"want_response_signed": true,
"audience": "https://app.example.com/saml/metadata",
"acs_url": "https://app.example.com/saml/acs",
"nameid_format": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
}
}
If your SP has separate toggles for response signature and assertion signature, turn on the one it actually validates. Many SP libraries validate assertion signatures only.
What you should see: the SP saves the IdP certificate and exposes no certificate parse error.
Step 6: Align signed assertion behavior between Okta and the SP
In Okta, open:
Applications → Applications → <your app> → Sign On → Edit
Set the signature-related options to the values your SP expects. If your SP validates assertions, use signed assertions. If it validates responses too, enable both where available in your org UI.
Use these target values:
| Setting | Value |
|---|---|
| Response | Signed if your SP checks response signature |
| Assertion Signature | Signed |
| Signature Algorithm | RSA-SHA256 |
| Digest Algorithm | SHA256 |
What you should see: the saved app settings show SHA-256 signing and signed assertions enabled.
Step 7: Assign a test user and run an IdP-initiated sign-in
In Okta:
Applications → Applications → <your app> → Assignments → Assign → Assign to People
Pick a user whose Okta profile has the exact email or username value your SP expects.
Then launch the app from the Okta end-user dashboard, or use the app embed link if your org exposes one.
What you should see: the browser posts a SAMLResponse to https://app.example.com/saml/acs and lands in your app as the assigned user.
Verify it works
First, verify the ACS endpoint is reachable and not redirecting to a non-SAML page:
curl -I https://app.example.com/saml/acs
Expected shape:
HTTP/2 200
content-type: text/html; charset=utf-8
A common bad shape is a login redirect instead of accepting POSTs:
HTTP/2 302
location: /login
Next, inspect the SAML assertion in your browser’s SAML tracer and confirm these three values:
Subject/NameID Format = urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
Subject/NameID = dev@example.com
Audience = https://app.example.com/saml/metadata
Finally, verify the certificate in metadata is parseable:
python3 - <<'PY' > okta.pem
import re
xml=open('okta-idp-metadata.xml').read()
cert=re.search(r'<X509Certificate>([^<]+)</X509Certificate>', xml).group(1)
print('-----BEGIN CERTIFICATE-----')
for i in range(0,len(cert),64): print(cert[i:i+64])
print('-----END CERTIFICATE-----')
PY
openssl x509 -in okta.pem -noout -subject -issuer -dates
Expected shape:
subject=CN = Okta SAML Signing Certificate
issuer=CN = Okta SAML Signing Certificate
notBefore=...
notAfter=...
Common pitfalls
Audience URI differs by one character
Mistake: Okta Audience URI is https://app.example.com/saml but the SP expects https://app.example.com/saml/metadata.
Symptom: SP logs show Audience restriction validation failed, Invalid audience, or audience mismatch.
Fix: Replace Okta Audience URI (SP Entity ID) with the exact entityID string from SP metadata.
NameID format is EmailAddress but the SP expects Unspecified
Mistake: Okta sends urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress while the SP library is hard-coded for unspecified.
Symptom: Login fails after assertion receipt; SP logs show unsupported NameIDPolicy, invalid subject, or it maps the wrong user.
Fix: In Okta Sign On → Edit, set Name ID format to Unspecified and retry.
Response is signed, assertion is not
Mistake: Okta signs only the SAML response, but your SP validates only the assertion signature.
Symptom: SP logs show Signature missing, No signature found on assertion, or Invalid document signature.
Fix: In Okta app signing settings, enable Assertion Signature: Signed and keep RSA-SHA256.
SP uses the wrong Okta certificate after a signing cert rotation
Mistake: The SP still trusts an old Okta signing certificate.
Symptom: Existing setup suddenly fails with signature validation failed even though URLs and audience are unchanged.
Fix: Re-download Okta metadata, import the current <X509Certificate>, and reload the SP config.
ACS URL points to a GET login page instead of the SAML POST handler
Mistake: Okta Single sign-on URL is set to /login instead of the SP’s ACS endpoint.
Symptom: Browser gets a 302 loop or your app shows a normal login page after Okta sign-in.
Fix: Replace Single sign-on URL with the exact ACS Location from SP metadata, typically something like https://app.example.com/saml/acs.
This article was written by an AI system and published pending human review. Verify anything you intend to act on.
Have a project in mind?
Get an instant AI price estimate for it, or talk directly to our team.
One email a month on what we learn building with AI