An interactive demo website showcasing the OAuth 2.0 PKCE (Proof Key for Code Exchange) authorization flow. This application is fully customizable for testing with any OAuth 2.0 compliant authorization server.
- OAuth 2.0 PKCE Flow: Complete implementation of the Authorization Code flow with PKCE (RFC 7636)
- Configurable OAuth Server: Set custom OAuth server, client ID, and scopes at runtime
- Token Management: Display and manage access tokens, refresh tokens, and ID tokens
- User Information: Fetch and display user info from the OIDC userinfo endpoint
- Token Refresh: Refresh access tokens using the refresh token grant
- Logout: Securely logout and clear stored tokens
- Dark UI: Modern, responsive dark theme for better OAuth server testing experience
- Frontend Framework: SolidJS - A lightweight, reactive JavaScript framework
- Build Tool: Vite - Next generation frontend tooling
- Styling: Tailwind CSS - Utility-first CSS framework
- Type Safety: TypeScript - Full type safety across the application
- Authentication: JWT decoding with proper type safety
src/
├── config/ # OAuth configuration and endpoints
│ └── oauth.ts # Centralized OAuth config and URL builders
├── lib/ # Utility functions
│ ├── storage.ts # LocalStorage abstraction layer
│ ├── crypto.ts # PKCE generation and cryptographic utilities
│ └── errors.ts # Custom error types for better error handling
├── services/ # Business logic and API clients
│ └── oauth-client.ts # OAuth 2.0 client implementation
├── types/ # TypeScript type definitions
│ └── index.ts # OAuth types (tokens, config, user info)
├── hooks/ # Custom Solid hooks
│ └── auth.ts # Main authentication hook with all OAuth functions
├── components/ # Reusable UI components
│ ├── Settings.tsx # OAuth configuration form
│ ├── User.tsx # User info display and token management
│ ├── TextInput.tsx # Editable text input component
│ └── CopyTextInput.tsx # Read-only input with copy functionality
├── pages/ # Page components
│ ├── Home.tsx # Main page (Settings or User based on auth state)
│ └── authz/
│ └── Callback.tsx # OAuth callback handler
├── App.tsx # Root component
├── index.tsx # Application entry point
├── index.css # Global styles
└── routes.tsx # Route definitions
- Config Layer: All OAuth endpoints and constants centralized in
src/config/oauth.ts - Service Layer: OAuth API client isolated in
src/services/oauth-client.ts - Storage Layer: LocalStorage abstraction in
src/lib/storage.tsfor reusability - Utilities: Crypto functions and error handling in dedicated modules
- Comprehensive TypeScript interfaces for all OAuth types
- Proper typing for tokens, user info, and configuration
- No generic
anytypes - all data structures are properly typed
- Custom error classes (
OAuthError,TokenExchangeError,ValidationError) - Consistent error messaging across the application
- User-friendly error display in components
- Uses
crypto.getRandomValues()instead ofMath.random()for secure random generation - Proper PKCE implementation with SHA256 code challenges
- Secure state parameter generation
- Removed module-level side effects (moved to effect hooks)
- Proper state management with loading and error states
- Better UX with feedback during async operations (e.g., "Refreshing..." button state)
- Set Your OAuth Server: Enter the OAuth 2.0 authorization server URL
- Set Client ID: Your registered OAuth client ID
- Set Scopes: OAuth scopes (default: "openid offline")
- Callback URL: Use the displayed callback URL in your OAuth server configuration
Create an .env file with:
VITE_BASE_URL=http://localhost:5173
VITE_AUTH_URL=https://your-oauth-server.com
VITE_AUTH_CLIENT_ID=your-client-id# Install dependencies
pnpm install
# Start dev server
pnpm dev
# Build for production
pnpm buildThis application implements the Authorization Code flow with PKCE:
- User clicks "Continue": Application generates a code verifier and challenge
- Redirect to Authorization Server: User is redirected to login and consent
- Callback: Server redirects back with authorization code
- Token Exchange: Application exchanges code for tokens (using code verifier)
- User Logged In: Tokens are stored and user info is displayed
- Token Refresh: User can refresh access tokens without re-authenticating
- Logout: Clear tokens and redirect to logout endpoint
PKCE (RFC 7636) adds a layer of security to the Authorization Code flow by:
- Preventing authorization code interception attacks
- Protecting against certain malware attacks
- Recommended even for confidential clients
useLogin()- Initiate OAuth login flowuseLogout()- Clear tokens and logoutuseRequestTokensByAuthorizationCode(code)- Exchange authorization code for tokensuseRefreshToken()- Refresh access tokenuseUserInfo()- Fetch user informationuseIsLogin()- Check if user is authenticateduseAccessToken()- Get current access tokenuseIDToken()- Get current ID tokenuseReadRefreshToken()- Get current refresh token
OAuthClient.getAuthorizationUrl()- Build authorization URL with PKCEOAuthClient.exchangeAuthorizationCode()- Exchange code for tokensOAuthClient.refreshAccessToken()- Refresh tokenOAuthClient.getUserInfo()- Fetch userinfo endpointOAuthClient.getLogoutUrl()- Build logout URL
This demo is designed to work with any OAuth 2.0 PKCE-compliant authorization server:
- Google OAuth: Configure with your Google Client ID
- GitHub OAuth: Configure with your GitHub OAuth App
- Keycloak: Deploy locally or use a hosted instance
- Auth0: Create an Auth0 application
- Custom Servers: Any RFC 6749 compliant OAuth server
Just update the configuration at runtime or in environment variables.
Found a bug or want to improve? Feel free to open an issue or submit a pull request!