This final phase turns TaskFlow from a working demo into something you could actually ship. We start with two things that matter before anything else: making sure the secrets scattered across every .env.local variable from this course are handled safely, and learning to actually watch what Okta is doing in real time when something goes wrong.
Step 1: Take Stock of Every Secret TaskFlow Now Holds
Across this course, TaskFlow's .env.local has accumulated a genuinely sensitive set of values. Worth listing them out explicitly, since a security review starts with knowing exactly what you're protecting:
OKTA_ORG_URL=https://integrator-545125.okta.com OKTA_CLIENT_ID=... # Phase 1 — public, not secret OKTA_CLIENT_SECRET=... # Phase 1 — secret OKTA_SERVICE_CLIENT_ID=... # Phase 6 — public, not secret OKTA_SERVICE_PRIVATE_KEY=... # Phase 6 — secret, high sensitivity OKTA_HOOK_SECRET=... # Phase 6 — secret
Not everything in that file is equally dangerous if leaked. OKTA_CLIENT_ID and OKTA_SERVICE_CLIENT_ID are meant to be public — they're sent in URLs and requests as a matter of course, similar to a username. OKTA_CLIENT_SECRET, OKTA_SERVICE_PRIVATE_KEY, and OKTA_HOOK_SECRET are the ones that matter: anyone with the client secret could impersonate TaskFlow's backend in the token exchange; anyone with the private key could authenticate as your Management API service app with full okta.users.manage access; anyone with the hook secret could call your inline/event hook endpoints and feed them fake data.
Step 2: Confirm .env.local Genuinely Isn't Tracked by Git
This was flagged back in Phase 1, but it's worth verifying directly rather than trusting memory, especially before deploying:
git check-ignore -v .env.local
If this prints a line showing .gitignore matched the file, you're safe. If it prints nothing, .env.local is not ignored, and you need to check immediately whether it was ever committed:
git log --all --full-history -- .env.local
If that shows any commits, the secrets inside are compromised the moment the repository is pushed anywhere public — even a single old commit is enough, since Git history preserves it permanently unless rewritten. If this happens, the fix isn't just deleting the file going forward — it's rotating every secret that was ever in it (generating a new Client Secret in Okta, a new Service App private key, a new hook secret) and removing the file from Git history entirely (a git filter-repo or similar history rewrite, plus force-push — genuinely disruptive, which is exactly why prevention matters more than cleanup here).
Step 3: Never Ship Secrets to the Browser
A mistake worth naming directly, because Next.js makes it easy to make by accident: any environment variable prefixed with NEXT_PUBLIC_ gets bundled into client-side JavaScript and is visible to anyone who opens their browser's DevTools. None of the variables above should ever carry that prefix. Every value TaskFlow uses — Client Secret, private key, hook secret — is read only inside Route Handlers, Middleware, or Server Components, all of which run exclusively on the server. If you ever find yourself needing a secret inside a "use client" component, that's a sign the logic belongs in a Server Action or Route Handler instead, not that the variable should be exposed.
Step 4: Set Production Environment Variables Properly on Deploy
When TaskFlow eventually deploys (covered later in this phase), .env.local itself never gets uploaded anywhere — it's for your machine only. Production secrets get entered directly into your hosting platform's own environment variable settings (e.g., Vercel's Project Settings → Environment Variables), scoped to the Production environment specifically. This means production and local development can safely use entirely different Okta credentials — a good practice covered in the next post when we set up a separate Okta Application for production.
Step 5: Learn to Read Okta's System Log
Every debugging session in this entire course — the "Bad Request" errors, the "not assigned to app" failures, the redirect issues — could have been diagnosed faster with one tool: Okta's System Log, the complete, real-time record of every authentication event, policy decision, and admin action in your org.
Where to Find It
Go to Reports → System Log in the Admin Console. By default, it shows the last seven days of activity across your entire org, displayed as a searchable table plus summary graphs at the top.
Reading a Single Event
Click the arrow on the right side of any row to expand it. Each event includes:
- eventType — a specific, dot-separated identifier for exactly what happened (e.g.,
user.session.start,user.authentication.auth_via_mfa,policy.evaluate_sign_on). - actor — who or what triggered it (a specific user, or a system process).
- target — what the event affected (a user, an app, a policy).
- outcome —
SUCCESSorFAILURE, plus areasonwhen it failed — often the exact detail a generic browser error page hides from you. - client — IP address, user agent, and geolocation of the request.
Practical Queries Worth Knowing
The System Log's search field accepts structured queries, not just plain text. A few genuinely useful ones for the kind of debugging this course has walked through:
Every sign-in-related event for a specific user, replacing the user ID:
(eventType eq "user.session.start") or (eventType eq "policy.evaluate_sign_on") or (eventType eq "user.authentication.verify") or (eventType eq "user.authentication.auth_via_mfa")
Only failed events, to jump straight to what broke:
outcome.result eq "FAILURE"
Everything related to a specific IP address (useful when you're testing from your own machine and want to isolate just your traffic):
client.ipAddress eq "<your IP here>"
Debugging From a User's Own Profile
There's also a narrower, faster view for a single user: go to Directory → People, open the specific user, and click View Logs. This filters the System Log down to just that person automatically — exactly what you'd want when a specific test account (like john doe or john@doe.com from earlier in this course) is behaving unexpectedly.
Why This Matters Looking Back
Every single Okta-side error worked through earlier in this course — the missing Access Policy rule, the "Any two factors" MFA mismatch, the missing group assignment for self-service registration — would have shown up here as a FAILURE outcome with a specific reason, well before it ever reached your Next.js app's error page. Going forward, the System Log should be the first place you check whenever an Okta-related request fails and the reason isn't obvious from your own application's logs.
Where TaskFlow Stands
Every secret TaskFlow depends on has a clear sensitivity level and a confirmed-safe home outside of Git, with a real plan for what to do if that assumption ever turns out to be wrong. You also now have the single most useful debugging tool for anything Okta-side going forward — the System Log — which would have made several of the errors worked through earlier in this course immediately obvious.
In the continuation of phase 7 we will cover testing authentication flows and deploying TaskFlow to Vercel with production Okta settings.
No comments:
Post a Comment