clientSecret securely — a secret never exposed to browsers, mobile apps, or end users. Server-rendered apps, API backends, and background services are typical confidential clients.
If any part of your app runs in a browser or on a user’s device, use PKCE instead. Client secrets in browser code are not secret.
Flow overview
1
Redirect the browser to Ave
From your server, construct the authorization URL and redirect the user’s browser to
https://aveid.net/signin. You can still include PKCE parameters — this is actually recommended even for confidential clients, as defense-in-depth.2
Receive the callback on your server
Your server endpoint at the registered
redirect_uri receives ?code=...&state=.... Validate state against the value stored in the user’s server session before proceeding.3
Exchange the code with your client secret
4
Verify the ID token
exchangeCodeServer returns the tokens as Ave sent them. Verify the id_token before creating a session:5
Store tokens server-side and issue a session
Store
access_token, access_token_jwt, id_token, and refresh_token in your encrypted server-side session store. Issue your own session cookie to the browser.Never send raw Ave tokens to the browser — issue your own short-lived session identifier instead.6
Refresh silently when tokens expire
Encryption keys and server callbacks
Encryption keys are delivered in the callback URL fragment, which browsers do not send to servers. A server-rendered callback route receives the code but never the keys. If your app requests an encryption scope, have the callback page read the fragment in client code withextractAppKeyFromUrl or mergeAppEncryptionFromUrl from @ave-id/sdk, keep the keys on the client, and call stripSensitiveFragmentParams(). The code exchange can still happen on your server.
Client secret rules
Store the secret in encrypted runtime config (environment variables, secrets manager)
Never ship
clientSecret to browsers, mobile apps, or frontend codeRotate secrets in the developer portal and your deployment environment at the same time
Log token endpoint failures without logging raw token values or secrets
Handling refresh token rotation
Ave rotates refresh tokens on every use — the old token is immediately invalidated after a successful refresh. If you store the old token and try to reuse it, you’ll getinvalid_grant.
Best practice:
- Store the new
refresh_tokenfrom every refresh response before discarding the old one - Use a database row lock or atomic update to prevent concurrent refreshes from the same token
- If refresh fails with
invalid_grant: stop retry loops, clear the session, and force re-authentication
