Skip to content

Authentication & Authorization

Authentication & Authorization is the security foundation of RTC Agent. Users log in via the OAuth2 authorization code flow, and the system maintains sessions using dual tokens (Access + Refresh). It supports parallel multi-device logins and automatic token refresh — users only need to sign in once for long-term use.

StepDescription
1User clicks the login button, and a login dialog appears
2The dialog displays the OAuth2 Provider’s authorization page via an iframe
3User completes authorization on the Provider page (e.g., GitHub, Google)
4After successful authorization, the system obtains the authorization code and exchanges it for tokens
5Tokens are stored in the browser locally, and login is complete

💡 Design Principle: The login flow is fully delegated to the OAuth2 Provider — RTC Agent never handles user passwords; security is guaranteed by the Provider.

TokenValidityPurposeStorage
🔑 Access Token1 hourAccess API and WebSocketPlaintext (short validity, manageable risk)
🔄 Refresh Token30 daysRefresh Access TokenHash only (plaintext returned once at issuance, then discarded)

📌 Security Key Point: The Refresh Token’s plaintext is only returned once at issuance; afterward, the server stores only the hash. Even if browser storage is compromised, attackers cannot impersonate the user long-term.

The system automatically refreshes tokens at multiple trigger points, completely transparent to the user:

TriggerDescription
⏱️ Token about to expireAutomatically refreshed 5 minutes before expiration to avoid request interruption
📱 Page returns to foregroundToken status is checked when switching back from background; refresh immediately if expired
🔌 Establishing WebSocketRefresh token on demand during connection to ensure validity

💡 Refresh failures don’t leave users in a “half-dead” state — the system logs them out directly and guides them to re-authenticate.

ConceptDescription
🔖 Device IDUnique browser identifier (UUID), automatically generated on first visit
📛 Device NameAutomatically inferred from OS (e.g., “Mac”, “Windows PC”, “Linux PC”)
🔀 Multi-deviceThe same user can log in independently on multiple devices without interference

📌 Tokens are independent per device — logging out on Device A does not affect the session on Device B.

PhaseDescription
🔗 ConnectWebSocket connection carries the Access Token for authentication
✅ VerifyServer validates token validity; invalid tokens are rejected
📡 SubscribeAfter authentication, subscribe to the user-specific channel to receive real-time messages
🔁 DisconnectReconnection requires re-authentication to ensure security

💡 Channel Isolation: Each user can only receive messages from their own channel and cannot access other users’ data.

ConstraintMechanismPurpose
🛡️ CSRF ProtectionUse state parameter during OAuth2 authorizationPrevent cross-site request forgery attacks
🏷️ Channel IsolationUsers can only subscribe to their own dedicated channelPrevent data leaks and unauthorized access
💾 Token StorageTokens stored only in browser locallyNot sent to third parties, reducing leak risk
🔑 Refresh TokenPlaintext returned once; server stores hash onlyCannot be used long-term even if storage is compromised
ScenarioUser-facing behavior
❌ Authorization failedLogin dialog shows error message; retry is available
⏱️ Token expired and refresh failedAutomatically logged out; login page displayed
🔌 WebSocket authentication failedConnection disconnected; user prompted to log in again

RTC Agent Server is an OAuth2 consumer — it needs to connect to an OAuth2 provider to authenticate users. The development environment includes a built-in mock-oauth2 as a sample provider; for production deployments, you need to provide your own OAuth2 service.

RTC Agent Server handles JWT issuance and device management; your OAuth2 service is only responsible for verifying user identity and returning user information.

Your OAuth2 service only needs to implement 2 endpoints:

Endpoint 1: Authorization Page — GET /oauth2/authorize

Section titled “Endpoint 1: Authorization Page — GET /oauth2/authorize”

Accessed directly by the browser (loaded via iframe), used to display the login/authorization UI.

Request (assembled by RTC Agent Server, accessed by the browser):

GET /oauth2/authorize?state=<hex>&client_id=<id>&redirect_uri=<uri>
ParameterDescription
stateAnti-CSRF random string, must be echoed back as-is
client_idClient identifier
redirect_uriCallback URL after successful authorization

Behavior requirements:

  1. Display a login/authorization page (can be your existing login system)
  2. After user authorizes, generate a short-lived, single-use authorization code
  3. HTTP 302 redirect to redirect_uri with code and state in the query string:
Location: <redirect_uri>?code=<code>&state=<state>

Page constraints:

  • The page will be loaded in an iframe — you must not set X-Frame-Options: DENY or a restrictive Content-Security-Policy: frame-ancestors
  • Content-Type must be text/html; charset=utf-8

Endpoint 2: Code Exchange — POST /oauth2/token/exchange

Section titled “Endpoint 2: Code Exchange — POST /oauth2/token/exchange”

Called server-to-server directly by RTC Agent Server, exchanging the authorization code for user identity.

Request:

POST /oauth2/token/exchange
Content-Type: application/x-www-form-urlencoded
Accept: application/json
client_id=<id>&client_secret=<secret>&code=<code>&redirect_uri=<uri>

Success response (200):

{
"provider_user_id": "user-12345",
"username": "John Doe",
"email": "john@example.com",
"avatar_url": "https://example.com/avatar.png"
}
FieldRequiredDescription
provider_user_idStable unique identifier for the user in your system — must be the same value for the same user every time
usernameOptionalDisplay name
emailOptionalEmail address
avatar_urlOptionalAvatar URL

Error responses:

{
"error": "invalid_client",
"error_description": "Invalid client_id or client_secret"
}
HTTP Statuserror valueMeaning
400invalid_requestMissing or invalid parameters
400invalid_grantAuthorization code is invalid, already used, or expired
401invalid_clientInvalid client credentials
500server_errorInternal server error
ConstraintDescription
Single-useThe same code can only be exchanged once
Short-livedRecommend expiry within 10 minutes
User-boundThe code must be associated with the authenticated user’s identity
  • ❌ No need to issue access_token / refresh_token — RTC Agent Server issues JWTs itself
  • ❌ No need to implement a standard OAuth2 /token endpoint — /oauth2/token/exchange is essentially a user info endpoint
  • ❌ No need to support scope, PKCE, or other extensions

After implementing your OAuth2 service, point the Server config to it:

providers:
mock:
enabled: true
url: "https://your-oauth-server.com" # Your OAuth2 service address
client_id: "your-client-id" # client_id agreed with your service
client_secret: "your-client-secret" # client_secret agreed with your service

⚠️ The mock in providers.mock is the provider name (it doesn’t mean “test only”). The Server will concatenate {url}/oauth2/authorize and {url}/oauth2/token/exchange as the two endpoint addresses. If your service uses different paths, you’ll need to extend BuildProviderClients or keep the paths consistent.