Skyline-ATS · For the customer's IT team
Everything needed to connect one Okta org to a Skyline-hosted training portal. Work through it once and it is done — the checks at the end exist because each one has previously cost a round trip on a comparable setup.
Learners open a training address, sign in with the Okta credentials they already have, and go straight into their course. We never see or store a password, and we hold no client secret — the connection is a public OpenID Connect client using PKCE.
Admin → Applications → Applications → Create App Integration
Choose OIDC – OpenID Connect, then Single-Page Application. The application type matters more than it looks — see the note at the bottom.
The app → General → Sign-in redirect URIs
We will send an exact list with this document — one per training address. Okta matches these character for character, so paste them rather than retyping.
https://<training-address>/auth/callbackThe app → Assignments
An Okta app that nobody is assigned to is fully configured and completely unusable. Every automated check passes and every real person is refused at sign-in.
Security → API → Authorization Servers
We request openid, email and profile. The
profile scope is what carries the learner's name, and the name is what a
completion certificate prints — without it a certificate shows an email address.
Security → API → Authorization Servers
This decides the issuer URL you send us, and it is the value most often sent wrong. Okta has two kinds and they produce different issuers:
https://<your-org>.okta.comhttps://<your-org>.okta.com/oauth2/<server-id>The app → General → Sign-out redirect URIs
Signing out of training clears the training session only and leaves your Okta session alone, so no sign-out URL is required. Tell us if you would rather signing out of training also ended the Okta session — be aware that would sign them out of anything else using it — and we will send exact values to register.
Your DNS provider · one CNAME per training address
Only needed if the training runs on your own domain. If we have given you an
address ending in .learn.skyline-ats.dev, that is already live — skip this step.
academy.example.com CNAME connect.skyline-ats.devThat is everything we need. Neither is a secret.
| Value | Where to find it | Example |
|---|---|---|
| Issuer URI | Security → API → Authorization Servers, the Issuer URI column | https://acme.okta.com/oauth2/default |
| Client ID | The app integration → General | 0oa1b2c3d4EfGhIjK5d7 |
These share a shape: the configuration looks complete, every obvious check passes, and something still fails when a real person tries to sign in.
The commonest Okta failure by a distance. Everything validates — the issuer resolves, the redirect URI is accepted, the scopes exist — and every actual person is refused, because an Okta app grants nothing until people or groups are assigned to it.
A Web app is issued a client secret and treated as confidential. We are a public client using PKCE and hold no secret, so sign-in fails at the token exchange — after the person has already typed their password, which makes it look like our fault.
Recreate it as a Single-Page Application. The secret cannot be removed from a Web app.
https://acme.okta.com and https://acme.okta.com/oauth2/default
are different issuers with different signing keys. Send the one the console shows.
And if you use a custom authorization server, its access policy has to include this application — otherwise every sign-in is refused with a message that reads like a scope problem.
They sit next to each other and accept identical-looking values. Filling only the sign-out field leaves sign-in failing with a redirect mismatch while the console looks correctly completed.