Build an OIDC Trust Settings Page
Build a policy form and API route that verifies trusted OIDC tokens.
Introduction
30 Second Summary
A secret copied into the wrong log or message can keep working long after the original task ends. That access stays open until someone spots the leak.
In this project, you will build a trust settings page with the shadcn OIDC registry that defines which token issuer and claims your API accepts. You will connect the policy to a Next.js API route that uses jose to allow matching short-lived tokens while rejecting the rest.
What You'll Build
You'll watch your local API allow a real short-lived token that matches your saved trust policy.
By the end of this project, you'll have:
- A policy form that catches an empty or malformed issuer before saving.
- A keyless API check that denies requests with missing or mismatched tokens.
- A verified allow response that shows the claims from a matching short-lived token.
- Secret Mission: Draw an architecture diagram that traces a token from its issuer to the final allow or deny response.
Are there any prerequisites?
You'll need Node.js plus access to a CI job or hosting platform that you control. That platform must be able to issue a real short-lived OIDC token.
The project creates a fresh Next.js app during the build.
Before We Start
A keyless API flow needs a working local app. It also needs a real token source you control.
You will prepare Node.js plus npm for the Next.js app. Visual Studio Code gives you an editor with a terminal.
You will also confirm access to the shadcn OIDC registry. Your own CI/CD job or hosting platform provides the short-lived OIDC token later.
In this step, get ready to:
- Verify a supported Node.js environment with npm.
- Prepare Visual Studio Code with its integrated terminal.
- Confirm access to the shadcn OIDC builder plus your controlled token source.
Verify Node.js and npm
Next.js requires Node.js 20.9 or higher. Installing Node.js also gives you npm for managing the app's packages.
- Press Cmd+Space on macOS or the Windows key on Windows to open system search.
- Type Terminal on macOS or PowerShell on Windows.
- Press Enter to open the terminal.
Before you run the checks, do you expect both commands to print version numbers?
- Check your Node.js and npm versions by running these commands:
node -v
npm -v
What Do These Checks Prove?
- The first command reports the installed Node.js version so you can compare it with the minimum requirement.
- The second command confirms that npm is available for installing project packages.
Choose the tab that matches what your terminal shows.
✔️ I see version 20.9 or higher
Your runtime supports the Next.js app. That clears the main compatibility check before you create any project files.
- Keep this terminal available for the next setup check.
ⓧ I see an older version
Your installed Node.js version is below the Next.js minimum. The current LTS release gives you a supported runtime with npm included.
- Open the official Node.js download page.
- Download the release labelled LTS for your operating system.
- Run the downloaded installer.
- Follow the installer prompts.
- Close your current terminal.
- Reopen the terminal through system search.
- Repeat the version check above.
You should now see a Node.js version above the minimum. You should also see an npm version.
ⓧ Command not found
The command is unavailable because Node.js is missing or your terminal has not loaded the installation yet. The LTS installer sets up Node.js plus npm.
- Open the official Node.js download page.
- Download the release labelled LTS for your operating system.
- Run the downloaded installer.
- Follow the installer prompts.
- Close every open terminal window.
- Reopen the terminal through system search.
- Repeat the version check above.
You should now see one version from Node.js. You should also see one version from npm.
Still Missing Version Numbers?
Restart your computer if the installer completed but the commands remain unavailable. This reloads the paths that your terminal uses to find programs.
If the issue continues, help me troubleshoot my Node.js and npm installation.
Prepare Visual Studio Code
Your editor keeps the project files beside the commands that run them. Visual Studio Code includes an integrated terminal for this workflow.
- Choose the tab for your operating system.
macOS
- Open the Visual Studio Code download page.
- Download the macOS installer.
- Open the downloaded .dmg file.
- Drag Visual Studio Code.app into the Applications folder.
Windows
The Windows installer guides you through a short setup flow.
- Open the Visual Studio Code download page.
- Download the User Setup installer for Windows.
- Run the downloaded .exe file.
- Follow the installer prompts.
- Press Cmd+Space on macOS or the Windows key on Windows to open system search.
- Type Visual Studio Code.
- Press Enter to open the editor.
- Select Terminal from the top menu.
- Select New Terminal.
You will see the TERMINAL panel at the bottom of Visual Studio Code. The command prompt shows that your editor and terminal are ready to work together.
Editor or Terminal Missing?
Reopen Visual Studio Code after the installation finishes. Use the top menu to create a new terminal if the panel stays hidden.
If the terminal still does not open, help me restore the Visual Studio Code integrated terminal.
Confirm the builder and token source
The registry builder previews a policy form from your provider plus library choices. Your controlled platform supplies the real short-lived token used later.
- Open the shadcn OIDC registry builder in your browser.
- Confirm that the page shows Components for building OIDC configuration interfaces.
- Confirm that the builder offers identity provider choices.
- Confirm that the builder offers form library choices.
- Confirm that the builder offers validation library choices.
Protect Your Credentials
Your credentials stay inside the platform's own sign-in flow. This step never asks you to copy a token.
Finding the right token source can feel vague because each provider names the feature differently. You only need to identify a job or hosting project you control that can issue an OIDC token.
- Sign in to a CI/CD or hosting platform you control.
- Identify one existing job or hosting project under your control.
- Open the official documentation site for that platform.
- Search the documentation for OIDC token.
- Confirm that your job or hosting project can mint a short-lived OIDC token.
Before the final check, do you expect Visual Studio Code to report the same runtime versions as your first terminal?
- Return to the integrated terminal in Visual Studio Code.
- Verify that the editor can access Node.js plus npm by running these commands:
node -v
npm -v
What Does This Final Check Prove?
Matching version output proves that Visual Studio Code can access the runtime from its integrated terminal. This is where you run the project commands in the next step.
- Return to the shadcn OIDC registry builder.
- Confirm that its policy form builder remains visible.
- Return to your controlled platform.
- Confirm that your chosen token source remains accessible.
Your workspace now has a supported runtime, an editor terminal, the OIDC builder, and a real token source. That foundation is ready for the keyless access flow.
Your environment is ready. Next up, you will use the builder to shape the trust policy form for your API.
Configure the OIDC Policy Form
Long-lived API keys stay useful until somebody rotates them. An OIDC trust policy replaces that open-ended trust with rules for short-lived tokens.
In this step, you will configure the shadcn OIDC registry builder for your token source. Its preview will show the trust-policy form your app needs.
In this step, get ready to:
- Open the shadcn OIDC registry builder.
- Complete the provider and library selections.
- Confirm the generated trust-policy form in the preview.
Review the builder layout
The builder keeps your configuration choices beside a live preview. This gives you immediate feedback before any components are copied into your app.
- Open the official shadcn OIDC registry builder in your browser.
- Locate the builder controls for the provider choices.
- Locate the builder controls for the library choices.
- Confirm the preview area is visible beside the controls.
The builder is ready. You now have one workspace for shaping the policy form before it reaches your app.
Select your provider and libraries
An identity provider represents the CI job or hosting platform that mints your short-lived token. Your selection should match the token source you control.
A form library manages each field's state. A validation library checks the entered values against rules.
- Select the identity provider that matches your token source in the provider chooser.
You'll see the preview refresh to reflect the provider selection.
- Select one option in the form-library chooser.
- Select one option in the validation-library chooser.
You'll see the preview refresh again with a generated form based on all three selections.
Preview not updating?
- Refresh your browser if the preview stops responding after a selection.
- Reselect each builder option if the preview still shows its starting state.
Help me troubleshoot a preview that does not update.
Verify the generated policy form
The issuer identifies the authority that minted a token. Required claims narrow trust to tokens carrying the values your policy expects.
Before you inspect the preview, which policy details do you expect the generated form to collect?
- Inspect the generated policy form in the preview.
- Identify the field that captures the issuer.
- Identify the area that captures required token claims.
- Confirm all three builder choices remain selected.
You have the core policy shape in place. The builder preview now shows an OIDC trust-policy form with issuer and required-claims fields.
Your policy form is configured. Next, you'll copy the generated components into a Next.js app and load the settings page locally.
Generate and Run the Settings App
Your shadcn OIDC registry builder now shows the trust-policy form you configured. The preview proves that your provider choices fit the form.
That form still lives outside your application. This step turns the preview into a local settings page inside a fresh Next.js app.
In this step, get ready to:
- Create a fresh local Next.js application.
- Copy the generated OIDC policy form into the application.
- Run the settings page to confirm that the policy form renders.
Create a fresh Next.js app
A fresh scaffold gives the generated registry files a predictable home. It also installs the dependencies needed to run the page locally.
Expect a few quiet minutes while npm downloads the dependencies.
- Scaffold my-app on your Desktop by running these commands:
cd ~/Desktop
npx create-next-app@latest my-app --yes
What do these commands do?
- The first command places your terminal on the Desktop.
- The second command creates the my-app directory from the default Next.js template.
- The --yes option applies the recommended defaults without opening the configuration prompts.
- Confirm that the generated project exists by running this command:
ls my-app
What does this check prove?
The command lists the files created inside my-app. A populated result confirms that the scaffold finished.
You should see the app directory in the output. The output should also include package.json.
Your local application shell is ready to receive the generated trust-policy components.
Did the scaffold fail?
Check that the terminal is still using the supported Node.js environment from the previous step. Remove only a partially created my-app directory before retrying the scaffold.
Confirm that npm can reach the package registry if the download stops.
Help me diagnose the Next.js scaffold failure.
Copy and connect the policy form
The builder generated a registry command from your selected provider setup. Running that command inside my-app copies the matching source files into your project.
- Return to the shadcn OIDC registry builder from earlier.
- Click Get Code.
- Click Copy Text beside the generated command.
- Save the copied command here: paste the generated command from Get Code.
npm may pause for permission before it downloads the shadcn CLI. Approving that download lets the generated command continue.
- Switch back to your terminal.
- Install the generated policy form inside my-app by running these commands:
cd ~/Desktop/my-app
[[OIDC_REGISTRY_COMMAND="paste the generated command from Get Code"]]
What does the generated command add?
- The first command makes my-app the active directory.
- The generated npx shadcn@latest add command copies the composed policy form into your application.
- The command also copies the provider implementation selected in the builder.
- The required form dependencies are added to the application.
- Confirm that the OIDC component files were copied by running this command:
ls components/oidc
What does this check prove?
The components/oidc directory holds the generated policy-form source. Listing it confirms that the registry command wrote files into your application.
You should see policy-form.tsx in the output. This is the composed form from your builder configuration.
Missing the OIDC components?
Confirm that you copied the complete command from Get Code. A shortened command can omit the composed form.
Check that your terminal is inside ~/Desktop/my-app before running the generated command.
Help me find the missing generated OIDC files.
The generated component now belongs to your project. A page must import it before a browser can render the form.
- Switch back to your code editor from earlier.
- Use the editor's folder picker to open ~/Desktop/my-app.
- Select app/page.tsx in the project tree.
- Replace the file contents with the following code:
// Render the generated OIDC trust-policy form on this page.
import { OidcPolicyForm } from "@/components/oidc/policy-form"
export default function Page() {
return <OidcPolicyForm />
}
What does this code do?
- The import loads OidcPolicyForm from the registry-generated component directory.
- The Page component renders the policy form at the application's home route.
- Save app/page.tsx.
✔️ Awesome, I've got everything!
Your page now imports the generated policy form. Keep the file saved for the local test.
ⓧ I'd like to double check the full code
Compare your saved app/page.tsx with this complete file.
// Render the generated OIDC trust-policy form on this page.
import { OidcPolicyForm } from "@/components/oidc/policy-form"
export default function Page() {
return <OidcPolicyForm />
}
Run the settings page
The development server compiles your new page whenever the browser requests it. The rendered result proves that the generated component can run inside your application.
Before you start the server, do you expect the browser to show the starter screen or your generated trust-policy form?
- Start the local development server by running this command:
npm run dev
What does this command do?
The command starts Next.js in development mode. The process stays active so the browser can load your local application.
- Open http://localhost:3000 in your browser.
You should see the generated OIDC trust-policy form. The page should include an issuer field plus the required-claims controls from your builder preview.
You made the jump from preview to product code with the trust-policy form now running locally.
Still seeing the starter page?
Confirm that you saved app/page.tsx inside my-app.
Check that the terminal running the development server is inside ~/Desktop/my-app.
Help me debug the missing policy form.
Your settings app is live. Next, you will test its validation with bad issuer values before saving a valid trust policy.
Validate and Save a Trust Policy
Your settings page now renders the generated OIDC policy form. A visible form still needs to prove that it blocks unsafe issuer values.
You will test the form with an empty issuer. You will repeat the check with a malformed URL.
Once those guardrails work, you will save the controlled issuer plus its required iss, aud, and sub claims.
In this step, get ready to:
- Trigger a validation error for empty issuer input.
- Confirm that a malformed issuer URL is rejected.
- Save a controlled issuer plus its required claims as a local trust policy.
Test empty issuer validation
Form validation decides whether an input can become part of the saved policy. The first test checks how the form handles a missing issuer.
- Return to the settings page from earlier.
- Remove all text from the issuer URL field.
- Predict whether the form can save an empty issuer.
- Use the form's submit control.
You'll see an inline validation message next to the issuer input. The submission stops at validation.
That first guardrail is working. Empty issuer data cannot become a trust policy.
Why issuer validation matters
The issuer identifies the token authority that your API can trust. Missing issuer data leaves the policy without an authority to verify.
No validation message appearing?
- Remove any spaces from the issuer input before submitting again.
- Use the form's submit control so the generated validator runs.
- Help me troubleshoot missing empty-issuer validation.
Test malformed issuer validation
A required field can still contain text that is not a usable URL. This test checks the issuer format rule.
- Enter not-a-url in the issuer URL field.
- Predict whether a non-empty value automatically passes validation.
- Use the form's submit control again.
You'll see another validation message beside the issuer input. Its wording depends on the validation library selected in the builder.
You have now proved both validation boundaries. The form rejects missing issuers plus malformed issuers.
Malformed issuer being accepted?
- Confirm that not-a-url is in the issuer input instead of the required-claims area.
- Submit through the form's control so the selected validation library checks the value.
- Help me debug malformed issuer validation.
Save a valid trust policy
A valid trust policy pairs a controlled issuer with precise claim expectations. These values become the acceptance conditions for later API checks.
How the claims fit together
- The iss claim identifies the token issuer. Its expected value must equal the saved issuer URL.
- The aud claim identifies the intended audience for the token.
- The sub claim identifies the expected workload or identity represented by the token.
Finding these three values can be fiddly because each provider exposes them differently.
- Return to the CI job or hosting platform from earlier.
- Record the controlled issuer URL from its token configuration or OIDC documentation here: your controlled issuer URL.
You now have the authority URL that the policy can trust.
- Record the audience configured for that token source here: your expected audience.
- Record the subject configured for that token source here: your expected subject.
You now have one controlled value for each policy condition.
- Return to the settings page from earlier.
- Enter your controlled issuer URL in the issuer URL field.
The issuer field now contains a URL from a token source you control.
- Set the expected iss claim to your controlled issuer URL.
- Set the expected aud claim to your expected audience.
The required-claims area now anchors the token issuer plus its intended audience.
- Set the expected sub claim to your expected subject.
- Predict whether the complete policy passes the form's validation rules.
- Use the form's submit control to save the policy.
The validation messages clear. Your settings page accepts the controlled issuer plus all three claim conditions.
- Predict whether a locally saved policy should survive a page reload.
- Refresh the settings page in your browser.
You'll see the issuer URL plus the expected iss, aud, and sub values remain populated. This proves the valid trust policy is stored locally.
Policy missing after refresh?
- Confirm that the expected iss value exactly matches the issuer URL.
- Check that the claim names use lowercase iss, aud, and sub.
- Save the policy again before refreshing the page.
- Help me troubleshoot local policy persistence.
Your saved trust policy now contains only validated inputs. Next up, you will connect that rule to an API route for its first deny response.
Add the Token Verification Route
Your settings page now saves a valid OIDC trust policy. Those rules cannot protect the API in your Next.js app until each request is checked against them.
In this step, you will install the generated verifier powered by jose. You will add an API route that returns a clear denial when a request has no token.
In this step, get ready to:
- Install the generated token verifier.
- Add an API route that checks incoming bearer tokens.
- Call the route without a token to prove the deny path works.
Install the generated verifier
The registry verifier discovers the issuer's public keys. It uses those keys to check each token's signature.
The verifier also checks expiry before comparing the token with your saved policy. A request only reaches the allow path after every check passes.
- Switch to a second terminal in the same Next.js app folder.
- Approve the download if the terminal asks for permission to fetch the shadcn CLI.
- Install the verifier by running this command:
npx shadcn@latest add @oidc/verify
What does this command add?
- The registry writes the server-side verifier to lib/oidc/verify.ts.
- The generated verifyOidcToken() function discovers the issuer's keys.
- The verifier checks the signature before it compares the required claims.
- Confirm lib/oidc/verify.ts now appears in your code editor's file tree.
Good progress. Your app now has the cryptographic check that turns the saved policy into an enforceable boundary.
Verifier file missing?
- Confirm the terminal is inside the same Next.js app folder that contains package.json.
- Check whether the installer is waiting for approval before it downloads the registry item.
Ask for help with the installer output: Why did the OIDC verifier installation fail in my Next.js app?
Create the verification route
A bearer token travels in the request's authorization header. The route extracts that token before passing it to the verifier.
Start with the deny path by using an empty policy list. This first pass proves that missing credentials never reach the allow response.
- Create app/api/oidc/verify/route.ts inside your Next.js app with the following code:
import { verifyOidcToken } from "@/lib/oidc/verify"
import type { OidcPolicy } from "@/lib/oidc/policy"
async function loadPolicies() {
// Replace with your storage.
const policies: OidcPolicy[] = []
return policies
}
export async function POST(request: Request) {
const token = request.headers.get("authorization")?.replace(/^Bearer\s+/i, "")
const policies = await loadPolicies()
const result = await verifyOidcToken(token, policies)
if (!result.ok) {
return Response.json(
{ ok: false, code: result.code, message: result.message },
{ status: 401 }
)
}
return Response.json({ ok: true, claims: result.claims })
}
What does this route do?
- The route reads the authorization header from the incoming request.
- The regular expression removes the bearer prefix before verification.
- The route passes the token plus the policy list to verifyOidcToken().
- A failed result returns a deny response with status 401.
- A successful result returns only verified claims.
- Save app/api/oidc/verify/route.ts.
Before you send the request, do you think the route will allow a caller that provides no bearer token?
- Call the route without an authorization header by running this command:
curl -X POST http://localhost:3000/api/oidc/verify
You will see a deny body whose code is missing-token. That result proves the request cannot enter the allow path without a token.
Route not responding?
- Confirm the development server is still running in the terminal from earlier.
- Check that the route file is located at app/api/oidc/verify/route.ts.
- Compare the import paths with the files inside your lib/oidc folder.
Get help tracing the request: Why is my local OIDC verification route not returning the missing-token denial?
Connect the saved policy
The route must load the same policy that your settings page saved earlier. This gives the verifier the trusted issuer plus the required iss, aud, and sub values.
The official route leaves loadPolicies() as the storage hook. Connect that hook to your existing local policy reader before accepting real tokens.
- Replace the empty policy array inside loadPolicies() with the read operation used by your existing local policy storage.
- Return the saved policy inside an OidcPolicy[] array.
- Save app/api/oidc/verify/route.ts.
Before you repeat the request, do you expect connecting the policy reader to change the decision for a missing token?
- Repeat the no-token request by running this command:
curl -X POST http://localhost:3000/api/oidc/verify
You will still see missing-token. The policy is available to the route without weakening the deny path.
Why is the same denial correct?
A saved trust policy describes which authenticated identities are acceptable. It never grants access to a request with no identity.
The next request must carry a signed token before the verifier can evaluate its issuer or claims.
✔️ Awesome, I've got everything!
Your verification route is saved. Its policy loader now reads the trust policy from your existing local storage.
ⓧ I'd like to double check the full code
Compare your route with the official structure below. Keep your existing storage read inside loadPolicies() in place of the empty reference array.
import { verifyOidcToken } from "@/lib/oidc/verify"
import type { OidcPolicy } from "@/lib/oidc/policy"
async function loadPolicies() {
// Replace with your storage.
const policies: OidcPolicy[] = []
return policies
}
export async function POST(request: Request) {
const token = request.headers.get("authorization")?.replace(/^Bearer\s+/i, "")
const policies = await loadPolicies()
const result = await verifyOidcToken(token, policies)
if (!result.ok) {
return Response.json(
{ ok: false, code: result.code, message: result.message },
{ status: 401 }
)
}
return Response.json({ ok: true, claims: result.claims })
}
That is the gate doing its job. Next up, you will send a real short-lived token through the same route and inspect its verified claims.
Verify a Matching OIDC Token
Your API route already rejects requests that arrive without a token. That proves the deny path is working.
Now you will test the positive path with a real short-lived OIDC token. The token must match every requirement in your saved trust policy before the route grants access.
In this step, get ready to:
- Mint a real short-lived token through your controlled issuer.
- Send the token to your local API route.
- Confirm that matching claims receive access while a missing token remains denied.
Prepare a live test credential
A short-lived OIDC token carries signed claims from your controlled issuer. Your route uses those claims to decide whether the request satisfies the saved policy.
A live token deserves careful handling. This test keeps exposure small because the token expires quickly.
- Switch back to the controlled CI job or hosting platform from earlier.
- Trigger the existing flow that mints a short-lived OIDC token.
- Confirm that the controlled process reports successful token issuance.
- Copy the freshly issued token through your platform's secure handoff.
- Keep the token out of your repository files.
Good. The live token is ready for one request without becoming part of your repository.
Exercise the allow path
The route expects the token as the request's bearer credential. It then verifies the token before comparing its issuer, audience, and subject with the saved policy.
Before you send the request, predict whether all three saved policy checks will match the token.
- Switch back to the request method from your earlier no-token check.
- Reuse the API route URL from that check.
- Attach the copied token as the request's bearer credential.
- Send the request.
You should receive an allow response containing the verified issuer, audience, and subject claims. Each returned value should match its requirement in the saved policy.
That is the keyless flow working. Your route accepted a short-lived identity proof because its verified claims matched the trust policy.
Still receiving a deny response?
- Mint a fresh token if the first token has expired.
- Compare the token issuer with the issuer saved in the policy.
- Compare the token audience with the audience saved in the policy.
- Compare the token subject with the subject saved in the policy.
Help me diagnose a denied matching OIDC token.
- Keep the live token outside the screenshot frame.
- Frame the allow response with its verified claims.
Protect the deny path
The successful request proves that a matching identity can enter. A final regression check confirms that the route still blocks requests with no identity proof.
Before you repeat the check, predict what the route will do after you remove the bearer credential.
- Remove the bearer credential from the request.
- Send the same request again.
You should receive the same clear deny response you saw earlier. No verified claims should appear.
Does the request still receive access?
- Confirm that the bearer credential was fully removed from the request.
- Confirm that you repeated the request against the same API route URL.
Help me find why my token-free request is still allowed.
Your two-path check is complete. Matching identities are allowed.
Requests without a token remain denied. Next, you will change one saved claim and prove that the same token loses access.
Reject a Policy Claim Mismatch
Your local API has already accepted a real short-lived OIDC token. That result proved the token matched the saved trust policy.
A trust policy protects the route only when every required claim matches. This step changes one expected claim so you can prove the same token loses access.
In this step, get ready to:
- Change the expected sub claim while leaving the token unchanged.
- Resend the previously allowed token to the local API route.
- Confirm the no-token request still receives a deny response.
Change one required claim
A controlled mismatch isolates the required-claim check. Changing sub keeps the saved issuer plus audience untouched.
- Append -mismatch to the expected sub value on the settings page from earlier.
- Save the updated trust policy with the form's save control.
You'll see the changed sub value remain in the saved policy. The token still carries its original subject claim.
Test the same token against the changed policy
The jose verifier still checks whether the token came from the trusted issuer. The required-claim comparison now finds a different expected subject.
Before you resend the request, consider whether the previously allowed token still satisfies the saved policy.
- Return to the terminal or request tool used for the successful allow test.
- Resend the request to the same local API route using the exact previously allowed token through the same authorization method.
You'll see a clear deny response because the saved sub expectation no longer matches the token's sub claim.
That denial is the result you wanted. Your API now proves that a valid signature alone cannot bypass the saved policy.
Why is a valid token denied?
Signature verification establishes who issued the token. It also confirms that the token has not been altered.
The saved policy adds authorization requirements for iss, aud, plus sub. A mismatch in any required value closes the route.
Does the token still receive access?
- Refresh the settings page from earlier.
- Confirm the required sub field retains the -mismatch suffix.
- Resend the request to the same local API route.
Help me debug the claim check.
Recheck the no-token denial
Changing a required claim must preserve the route's existing missing-token guard. This final check proves both denial paths remain active.
Before you repeat the earlier check, consider whether a request without a bearer token can reach claim verification.
- Return to the no-token request from earlier.
- Send the request again without a bearer token.
You'll see a clear deny response again. This confirms the missing-token guard still works after the policy change.
- Capture only the mismatched-token deny response in your screenshot.
- Keep the short-lived token outside the screenshot.
You have proved that your route denies both a missing token plus a signed token with the wrong required claim. The saved trust policy now decides exactly which verified identities receive access.
Secret mission
Map the OIDC Trust Boundary
Turn your working keyless access flow into a shareable architecture diagram. Map where trust begins. Show why missing or mismatched evidence ends in a deny response.
Clean Up Your Resources
Clean Up Your Resources
Because the Next.js app runs on your computer, the local project has no ongoing hosting cost. You can keep it running, pause it for later, or delete it entirely.
Check Your Token Provider
The CI job or hosting platform that supplied the short-lived token follows its own account plan. Any ongoing charge there depends on that provider.
Resources you used:
- Running local development server for the Next.js application.
- Local Next.js application folder containing the generated settings page and verification route.
- Saved local OIDC trust policy containing controlled test values.
- Temporary CI workflow or hosting configuration created only to mint the short-lived token, if applicable.
Keep everything running
This option keeps the trust-policy flow available for more controlled testing.
- Keep the local development server running.
- Retain the Next.js application folder as your working copy.
- Preserve the saved policy only while you need its controlled issuer for testing.
- Continue keeping the short-lived token outside the repository.
Pause - I'll come back to this later
Stopping the development server frees its port and system resources. Your application files remain ready for another session.
- Switch back to the terminal running the development server.
- Press Ctrl+C to stop the process.
- Confirm that the terminal returns to its command prompt.
- Leave the Next.js application folder in its current location.
- Retain the saved policy only if you plan to resume controlled testing.
Your local server is stopped. The settings page and verification route remain available in the application folder.
Delete - I don't want to use this again
Permanent removal deletes the local app and its project-only configuration. The following checks help you remove only the resources created for this project.
- Copy any project code you want to keep to a separate location.
- Switch back to the local settings page from earlier.
- Delete the saved OIDC trust policy from the local storage mechanism used by the settings page.
- Refresh the settings page.
The controlled issuer URL should no longer load into the form.
- Switch back to the terminal running the development server.
- Press Ctrl+C to stop the process.
- Confirm that the terminal returns to its command prompt.
The development server is now stopped. The folder removal steps depend on your operating system.
macOS
- Press Cmd+Space to open the macOS search bar.
- Type Finder.
- Press Enter to open Finder.
- Locate the Next.js application folder from earlier.
- Move the application folder to the operating system's deleted-items location.
- Open the deleted-items location.
- Remove only the Next.js application folder permanently.
Windows
- Press the Windows key to open the Windows search bar.
- Type File Explorer.
- Press Enter to open File Explorer.
- Locate the Next.js application folder from earlier.
- Move the application folder to the operating system's deleted-items location.
- Open the deleted-items location.
- Remove only the Next.js application folder permanently.
- Return to the CI job or hosting platform that supplied the short-lived token.
- Delete the temporary token-minting configuration if it was created only for this project.
- Keep any shared configuration that still supports another project.
- Confirm that the project-only configuration is no longer available to run.
That's the cleanup finished. Your project-only resources are no longer active.
Nice Work!
Nice Work!
You did it! Your Next.js app now saves an OIDC trust policy that its jose-based API route enforces against short-lived bearer tokens.
You've learned how to:
- Built a trust settings page from the shadcn OIDC registry. The form validates issuer input before saving required claims.
- Implemented token verification in an API route. The route verifies signatures against the issuer's keys. It also enforces the required iss, aud, and sub claims.
- Proved the full allow-or-deny flow with a controlled short-lived token. You saw verified claims in the allow response. You confirmed that a missing token produces a deny response. You changed one required claim to prove the same token is rejected.
- Secret Mission: Extended the project through an optional challenge that pushed your keyless access skills further.
Ready to quiz yourself?