PKCE Flow
PKCE (Proof Key for Code Exchange) is the recommended authentication method for browser-based applications and human users. The existing RSA admin portals use this flow via next-auth.
When to Use PKCE
- Building a web application that authenticates human users
- Admin portal integrations (TenantAdmin, PlatformAdmin)
- Any flow where a human must log in interactively
Flow Overview
Browser Your App IS7 (port 5000)
| | |
|-- Click "Login" -------> | |
| |-- Generate code_verifier |
| | code_challenge = SHA256 |
| |-- GET /connect/authorize -->|
|<-- Redirect to IS7 -------| |
| | |
|-- Enter credentials ----->| (IS7)|
|<-- MFA prompt (if req'd) ---| |
|-- Enter TOTP code ------->| (IS7)|
|<-- Redirect to your app + ?code=AUTH_CODE |
| | |
| |-- POST /connect/token ------>|
| | grant_type=authorization_code
| | code=AUTH_CODE |
| | code_verifier=... |
| |<-- access_token + id_token |
Implementation with NextAuth.js
The existing admin portals configure next-auth like this:
// app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
export const { handlers, auth } = NextAuth({
providers: [
{
id: "rsa",
name: "RSA Identity",
type: "oidc",
issuer: process.env.IDENTITY_AUTHORITY,
clientId: process.env.NEXTAUTH_CLIENT_ID,
clientSecret: process.env.NEXTAUTH_CLIENT_SECRET,
},
],
callbacks: {
async jwt({ token, account }) {
if (account?.access_token) {
token.accessToken = account.access_token;
}
return token;
},
async session({ session, token }) {
session.accessToken = token.accessToken as string;
return session;
},
},
});
Required Parameters
| Parameter | Value |
|---|---|
response_type | code |
client_id | Your app's client ID |
redirect_uri | Must match registered URI in IS7 |
scope | openid + required API scopes |
code_challenge_method | S256 |
code_challenge | BASE64URL(SHA256(code_verifier)) |
Registering a PKCE Client
Create an OAuth app via the Admin API:
curl -X POST http://localhost:5002/admin/api/v1/clients \
-H "Authorization: Bearer ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"appType": "ShopperApp",
"name": "My Shopper App",
"redirectUris": ["https://myapp.com/auth/callback"],
"scopes": ["shopper.read", "shopper.write"]
}'