# Rust OAuth Test Server
A fast, fully configurable, in-memory OAuth 2.0 + OpenID Connect authorization server for testing, zero-HTTP mode and DCR support for testing auth flow in MCP Servers and MCP Clients.
### Caution
This server was developed with the purpose of supporting testing and development of the [rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk), and may not be maintained or updated regularly. Please consider this when integrating or using this server in other contexts.
> ⚠️ Warning: not for production use - in-memory, no persistence, no rate limiting.
## Purpose
This server implements all major OAuth 2.0 flows and OpenID Connect core features in-memory, making it ideal for:
- Testing OAuth clients (web, mobile, SPA, backend)
- Specifically tailored for testing authentication flow MCP Servers and Clients, with DCR support
- End-to-end flow validation
- Local development
- Integration testing of authorization flows
- Local development against a real OAuth provider
- Demonstrating OAuth concepts
- CI/CD pipeline validation
## Supported Standards
| [RFC 6749](https://tools.ietf.org/html/rfc6749) – OAuth 2.0 | Full |
| [RFC 6750](https://tools.ietf.org/html/rfc6750) – Bearer Token | Yes |
| [RFC 7636](https://tools.ietf.org/html/rfc7636) – PKCE | Yes (`plain`, `S256`) |
| [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) – Dynamic Client Registration | Yes |
| [RFC 7662](https://tools.ietf.org/html/rfc7662) – Token Introspection | Yes |
| [RFC 7009](https://tools.ietf.org/html/rfc7009) – Token Revocation | Yes |
| [RFC 7519](https://tools.ietf.org/html/rfc7519) – JWT Access Tokens (RS256) | Yes |
| [OpenID Connect Discovery 1.0](https://openid.net/specs/openid-connect-discovery-1_0.html) | Yes |
| [OpenID Connect Core](https://openid.net/specs/openid-connect-core-1_0.html) | Partial (UserInfo, `sub`, `iss`) |
## Key Features
- **Dynamic Client Registration (DCR)** (`POST /register`) with full metadata support
- **Authorization Code Flow** with **PKCE** (`/authorize`, `/token`)
- **Refresh Token Flow** with rotation and revocation
- **Client Credentials Grant**
- **JWT Access Tokens** signed with **RS256** (auto-generated RSA key pair)
- **Token Introspection** (`POST /introspect`)
- **Token Revocation** (`POST /revoke`)
- **OpenID Connect Discovery** (`.well-known/openid-configuration`)
- **JWKS Endpoint** (`.well-known/jwks.json`)
- **UserInfo Endpoint** (`GET /userinfo`)
- **In-memory stores** (clients, codes, tokens) - no external DB required
- **Full error handling** with redirect errors and JSON error responses
- **State parameter**, **scope**, **redirect_uri validation**
## Endpoints
| Method | Path | Description |
|-------|------|-------------|
| `GET` | `/.well-known/openid-configuration` | OIDC Discovery |
| `GET` | `/.well-known/jwks.json` | Public keys for JWT validation |
| `POST` | `/register` | Dynamic client registration |
| `GET` | `/register/:client_id` | Retrieve registered client |
| `GET` | `/authorize` | Authorization endpoint (code flow) |
| `POST` | `/token` | Token endpoint (all grants) |
| `POST` | `/introspect` | RFC 7662 introspection |
| `POST` | `/revoke` | RFC 7009 revocation |
| `GET` | `/userinfo` | OIDC user info (requires Bearer token) |
| `GET` | `/error` | Human-readable error page |
## In-Memory Stores
- `clients`: `HashMap<String, Client>` - registered clients
- `codes`: `HashMap<String, AuthorizationCode>` - short-lived auth codes
- `tokens`: `HashMap<String, Token>` - access tokens (JWTs)
- `refresh_tokens`: `HashMap<String, Token>` - refresh token mapping
## Security & Testing
- **No persistence** - perfect for isolated tests
- **Auto-generated RSA key pair** on startup
- **PKCE verification** (`S256` and `plain`)
- **Token revocation propagation**
- **Expiration enforcement**
- **Scope and redirect_uri validation**
## Run as a Standalone Binary (Great for Manual Testing & Debugging)
You can run the server directly from your terminal - no code required.
### 1. Install it globally
```bash
cargo install oauth2-test-server
```
### 2. Start the server
```bash
oauth2-test-server
```
You’ll see:
```
OAuth Test Server running on http://127.0.0.1:8090/
• Discovery: http://127.0.0.1:8090/.well-known/openid-configuration
• Jwks: http://127.0.0.1:8090/.well-known/jwks.json
• Authorize: http://127.0.0.1:8090/register
• Token: http://127.0.0.1:8090/token
• Register: http://127.0.0.1:8090/authorize
• Introspection: http://127.0.0.1:8090/introspect
• UserInfo: http://127.0.0.1:8090/userinfo
• Revoke: http://127.0.0.1:8090/revoke
```
Quick test with curl:
```bash
# Register a client
curl -X POST http://localhost:8090/register -H "Content-Type: application/json" -d '{
"redirect_uris": ["http://localhost:8090/callback"],
"grant_types": ["authorization_code"],
"response_types": ["code"],
"scope": "openid profile email"
}'
```
## How to Use in Tests
```
#[tokio::test]
async fn my_oauth_test() {
let server = oauth2_test_server::OAuthTestServer::start().await;
println!("server: {}", server.base_url());
println!("authorize endpoint: {}", server.endpoints.authorize_url);
// register a client
let client = server.register_client(serde_json::json!({ "scope": "openid",
"redirect_uris":["http://localhost:8080/callback"],
"client_name": "rust-mcp-sdk"
}));
// generate a token for the client
let token = server.generate_token(&client, server.jwt_options().user_id("rustmcp").build());
assert_eq!(token.access_token.split('.').count(), 3);
assert_eq!(server.clients().read().iter().len(), 1);
assert_eq!(server.tokens().read().iter().len(), 1);
}
```
**⚠️ Warning: not for production use** - in-memory, no persistence, no rate limiting.