Integrate a confidential client with generative AI Developer
Last updated Aug 15, 2026
Integrate a confidential client with generative AI
This page is for developers who want generative AI to integrate confidential-client OAuth 2.1 / OpenID Connect (OIDC) sign-in. You can complete a basic integration by following the steps even if you have not studied the protocols in depth.
There are four steps:
- Give the prompt on this page to the AI.
- Register the Redirect URI the AI outputs in the Swaymoon Developer identifier wizard (choose Confidential client).
- Set the portal-issued
client_idandclient_secretas server environment variables. - Start the app and test the Sign in with Swaymoon Account button.
The prompt on this page targets apps that have a server runtime that can keep secrets. If the project ships as pure HTML, a static site, or browser-only, read Integrate a public client with generative AI and Minimal Python example instead. Do not invent a client_secret.
If you are unsure about the architecture, the prompt asks the AI to check first: is there a traditional backend, API Route, Serverless Function, or BFF (Backend for Frontend) that can store client_secret safely?
Critical security
client_secretauthenticates a confidential client. Keep it on the server only. Do not send it to the AI, and do not put it in frontend code, client-visible environment variables, or a Git repository. Public clients are not issued aclient_secret.
Step 1: Give the prompt to the AI
Open the project in an AI coding tool, then copy the entire prompt below.
Do not add real credentials to the prompt. The AI should implement the code first, then output the Redirect URI to register.
Integrate “Sign in with Swaymoon Account” in the current project. Apply the code changes and run any tests that are needed.
Interaction goals:
- Add a “Sign in with Swaymoon Account” button on a suitable sign-in page.
- After the user chooses the button, they go to the official Swaymoon page to sign in.
- After success they return to this app and stay signed in.
Check the project’s deploy and runtime shape first:
- If the project has a server, API Route, Serverless Function, or BFF that can keep client_secret safely, continue as a confidential client.
- If the project is pure HTML, a static site, or a pure SPA where token exchange can only happen in the browser: do not use a confidential client. Use a portal public client instead (clientType=public, token endpoint auth none) and implement PKCE token exchange with no client_secret (see “Integrate a public client with generative AI” and “Minimal Python example”).
- Never put client_secret in the browser or frontend code.
Integration settings:
- Issuer: https://api-passport.swaymoon.com
- Discovery: https://api-passport.swaymoon.com/.well-known/openid-configuration
- Flow: Authorization Code + PKCE (S256)
- With a server, client auth: client_secret_basic (confidential client). Frontend-only: none (public client; form includes client_id + code_verifier; no refresh_token)
- ID Token signing algorithm: ES256
- Prefer sign-in entry: GET /auth/swaymoon
- Prefer callback entry: GET /auth/swaymoon/callback
- Request openid only by default. Add email or specific profile fields (such as name, picture) only if this product truly needs them. Do not take a bundled profile.
Implementation requirements:
1. Prefer a maintained OIDC client library that fits the current framework, and take protocol endpoints from Discovery.
2. Generate and store state, nonce, and PKCE code_verifier on the server; validate them strictly on callback.
3. Exchange tokens using only SWAYMOON_CLIENT_ID and SWAYMOON_CLIENT_SECRET on the server.
4. Verify the ID Token ES256 signature with JWKS, and verify iss, aud, exp, iat, and nonce.
5. Call UserInfo on the server and confirm its sub matches the ID Token sub.
6. Look up or create a local user with sub. Do not use email as the user primary key. Interpret profile fields from the token scope; ungranted items are default placeholders, not real data.
7. Create this app’s own secure sign-in session. The browser only stores an app session Cookie with HttpOnly and a sensible SameSite. Do not store Swaymoon tokens in the browser. In production over HTTPS, Secure is required.
8. Post-sign-in redirects may only be in-site relative paths or a trusted allowlist, to avoid open redirects.
9. Do not store secrets or tokens in localStorage, sessionStorage, ordinary cookies, logs, error pages, or test snapshots.
10. Do not store secrets in public variable prefixes such as NEXT_PUBLIC_, VITE_, NUXT_PUBLIC_, PUBLIC_.
11. Create a .env.example with no real values, and make sure local secret files are ignored by .gitignore.
12. Do not ask me to send a real client_secret in the chat.
When you finish, give clear, actionable integration notes:
1. “Copy this entire line into the Swaymoon Developer portal”, then print the full Redirect URI for local development on its own line.
2. The full Redirect URI to register for production. If the production host is unknown, mark the parts that must be replaced.
3. Which environment variables I must set on the server, and where to fill them in the current framework or deploy platform. Show names only; do not show or guess secret values.
4. How to start the project, find the sign-in button, and complete one test.
5. Which files you changed.
After the AI changes the code, find output like this:
Copy this entire line into the Swaymoon Developer portal:
http://127.0.0.1:3000/auth/swaymoon/callback
The address above is an example. Use the port and path the AI outputs for the current project.
Step 2: Register the Redirect URI
What is a Redirect URI?
Redirect URI is Redirect URI in the Developer portal wizard: a callback endpoint registered on the OAuth client in advance. After the user authenticates and confirms authorization on Swaymoon Account, the authorization server redirects the browser here with the authorization response, such as code and state.
The Redirect URI usually maps to a callback route the AI created on your backend, not a normal home page. That route validates the authorization response, exchanges tokens, creates an app session, and redirects the user to the post-sign-in page.
A Redirect URI is usually app Origin plus callback path. Origin includes scheme, host, and port, for example https://app.example.com or http://127.0.0.1:3000.
App Origin + /auth/swaymoon/callback
Examples:
| Scenario | App address | Redirect URI |
|---|---|---|
| Local development | http://127.0.0.1:3000 | http://127.0.0.1:3000/auth/swaymoon/callback |
| Production site | https://app.example.com | https://app.example.com/auth/swaymoon/callback |
Prefer the full Redirect URI the AI outputs from the project’s routes and listen port. Do not guess.
Exact-match rules
redirect_uri in the authorization request must match the registered portal value character for character. This check prevents authorization codes from being sent to unregistered addresses. These differences count as different URIs:
http://versushttps://;127.0.0.1versuslocalhost;- port
3000versus3001; - a trailing
/may also differ.
Copy the AI’s URI in full. Do not edit it by hand. If the AI outputs local and production URIs separately, register each in the Developer portal.
Fill in the Developer portal
- Sign in to the Swaymoon Developer portal.
- Open Identifiers and click + to start Register an app identifier.
- Description: a name users will recognize on the consent page. With a server, choose Confidential client.
- Icon: use the default, or upload, crop, and continue.
- Redirect URI: paste the full Redirect URI from the AI (add local and production separately if needed).
- Capabilities: keep
openidrequired. Setemailonly if you need a contact address (required / optional / not requested). Profile fields can be optional or required (required needs a reason and privacy policy). The user may choose Hide My Email; treat it as a normalemail. See Scopes and consent. - After Confirm, click Register.
On success the portal shows client credentials (save them immediately):
client_id: public OAuth client identifier for the app that starts authorization;client_secret: confidential-client credential, shown only at creation. Save it securely at once (public clients do not have this field).
Step 3: Configure client credentials
The AI has usually already created a template like this:
SWAYMOON_ISSUER=https://api-passport.swaymoon.com
SWAYMOON_CLIENT_ID=
SWAYMOON_CLIENT_SECRET=
SWAYMOON_REDIRECT_URI=
Follow the AI’s notes for your framework and put real values in server environment variables.
- Locally, that is usually
.env.localor similar, already ignored by.gitignore. - For a deployed site, use the platform’s Environment Variables, Secrets, or equivalent settings page.
SWAYMOON_REDIRECT_URIis the full Redirect URI you just registered.- If the AI also asks for an app session secret, generate a random value with the command it gives in your local terminal, then fill the environment variable yourself. Do not send the generated value back to the AI.
Credential security
All of the following are forbidden:
- Do not paste
client_secretinto the AI chat; - Do not put
client_secretin HTML, React, Vue, or other frontend files; - Do not store it in frontend-public variables such as
NEXT_PUBLIC_,VITE_,NUXT_PUBLIC_,PUBLIC_; - Do not commit a
.envfile that contains real secrets to Git; - Do not store Access Token, ID Token, or Refresh Token in
localStorage.
If the AI wants client_secret in the frontend, stop using that implementation and have the server or BFF do the token exchange instead.
Step 4: Test sign-in
- Start the project with the command the AI gave you.
- Open the page that has the sign-in button.
- Choose Sign in with Swaymoon Account.
- Complete sign-in and authorization on the official Swaymoon page.
- The browser returns to your app and shows a signed-in state.
Users only need one sign-in button. Authorization redirect, callback checks, token exchange, and app-session creation all happen on the server.
<a href="/auth/swaymoon">Sign in with Swaymoon Account</a>
The AI generates the real button component and styles for the current project. You do not need to copy the HTML above by hand.
FAQ
You can give error text to the AI for help, but strip client credentials, tokens, and full callback query strings first. Do not send a full browser URL that contains code= or state=.
| Problem | How to check |
|---|---|
| Redirect URI mismatch | Copy the AI’s full URI again and compare it character by character with the portal registration |
invalid_client | Check that client_id and client_secret are in server environment variables, then restart the project |
| After authorization, the app never returns | Check that the Redirect URI for the current environment is registered in the portal |
| AI detected a frontend-only / static architecture | Switch to Integrate a public client with generative AI and Minimal Python example, or add a server that can keep secrets and continue on this page |
UserInfo has no email | Token lacks email (user unchecked or it was not requested). When granted, the field should always be present. Check scope in the token response |
| Avatar / nickname does not look real | Without the matching field scopes, UserInfo still has fields, but they are default placeholders (see Tokens and user info). Use scope to tell real data |
email looks like a privacy relay | The user chose Hide My Email on the consent page. Treat it as a normal email; do not ask for the real address |
For the full protocol and parameters, read Integration overview, Authorization code and PKCE, Tokens and user info, Scopes and consent, Examples and troubleshooting, and Minimal Python example. Client registration is Registration and configuration in this directory.