How to Add a New OAuth-Based Provider Using OmniRoute's resolvePublicCred() Pattern
OmniRoute's resolvePublicCred() utility allows developers to embed default OAuth credentials directly in the codebase while maintaining the ability to override them via environment variables, ensuring new providers can be registered securely in src/lib/oauth/constants/oauth.ts and exposed through the provider registry.
Adding a new OAuth-based provider to the OmniRoute repository (diegosouzapw/OmniRoute) requires following a specific credential resolution pattern to maintain security compliance. The resolvePublicCred() function, defined in the Open-SSE utilities, provides a fallback mechanism that checks for environment variables before using hard-coded defaults, as mandated by Hard Rule #11 and the project's security documentation.
Understanding the resolvePublicCred() Security Pattern
The resolvePublicCred() function is the central mechanism for handling public OAuth credentials in OmniRoute. Located in open-sse/utils/publicCreds.ts at line 213, this utility first checks for the presence of a specified environment variable, and if absent, returns a hard-coded default value that ships with the repository. This pattern ensures that the application works out-of-the-box for development while allowing production deployments to inject secure credentials via environment variables, as detailed in docs/security/PUBLIC_CREDS.md.
Step-by-Step Implementation Guide
1. Register the Provider Configuration in oauth.ts
Begin by defining a static configuration object in src/lib/oauth/constants/oauth.ts that contains the OAuth endpoints, scopes, and credential resolutions. Each provider requires an exported constant (e.g., MYPROVIDER_CONFIG) that uses resolvePublicCred() to define the clientId and clientSecret fields.
export const MYPROVIDER_CONFIG = {
authorizeUrl: "https://auth.myprovider.com/oauth/authorize",
tokenUrl: "https://auth.myprovider.com/oauth/token",
scopes: ["openid", "profile", "email"],
clientId: resolvePublicCred("myprovider_id", "MYPROVIDER_OAUTH_CLIENT_ID"),
clientSecret: resolvePublicCred("myprovider_secret", "MYPROVIDER_OAUTH_CLIENT_SECRET"),
redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/callback`,
};
2. Create the Provider Module
Create a new file at src/lib/oauth/providers/myprovider.ts that imports the configuration and exports a provider descriptor compatible with the OAuth service layer. This module defines the provider's metadata and links it to the configuration constant.
import { Provider } from "./types";
import { MYPROVIDER_CONFIG } from "../constants/oauth";
export const myprovider: Provider = {
id: "myprovider",
name: "MyProvider",
type: "oauth",
config: MYPROVIDER_CONFIG,
};
3. Export from the Registry Index
Expose the new provider by adding an export statement to src/lib/oauth/providers/index.ts, which serves as the barrel file for the OAuth registry. This allows the service layer to discover the provider automatically.
export * from "./myprovider";
export * from "./other-providers";
4. Verify Service Layer Integration
The generic OAuth handling logic in src/lib/oauth/providers.ts automatically discovers providers through the registry index and manages auth URL generation, token exchange, and refresh scheduling. No modifications are required unless the provider implements a non-standard OAuth flow, in which case custom logic should be added within the specific provider file.
5. Add Tests and Update Documentation
Create unit tests following the pattern established in tests/unit/zed-oauth-provider.test.ts to verify that resolvePublicCred() returns the expected format and that the configuration object resolves correctly. Additionally, update docs/reference/PROVIDER_REFERENCE.md to include the new provider in the OAuth providers table.
import { resolvePublicCred } from "../../open-sse/utils/publicCreds";
import { MYPROVIDER_CONFIG } from "../../src/lib/oauth/constants/oauth";
test("myprovider config resolves public cred", () => {
const clientId = resolvePublicCred("myprovider_id", "MYPROVIDER_OAUTH_CLIENT_ID");
expect(MYPROVIDER_CONFIG.clientId).toBe(clientId);
});
Key Files Reference
open-sse/utils/publicCreds.ts: DefinesresolvePublicCred()(line 213) andresolvePublicCredMulti()for credential resolution.src/lib/oauth/constants/oauth.ts: Contains provider-specific constants using theresolvePublicCred()pattern.src/lib/oauth/providers/index.ts: Barrel file that exports all provider modules for registry discovery.src/lib/oauth/providers.ts: Core service layer that consumes the registry and manages OAuth flows.docs/security/PUBLIC_CREDS.md: Security guidelines explaining the public credential pattern.docs/reference/PROVIDER_REFERENCE.md: User-facing documentation listing available providers.
Summary
- Define provider constants in
src/lib/oauth/constants/oauth.tsusingresolvePublicCred()for all public credentials. - Create individual provider modules in
src/lib/oauth/providers/and export them throughindex.ts. - The service layer in
src/lib/oauth/providers.tsautomatically handles discovery and OAuth flow management. - Environment variables take precedence over hard-coded defaults due to the
resolvePublicCred()fallback logic. - Always update unit tests and provider reference documentation when adding new OAuth integrations.
Frequently Asked Questions
What is the purpose of resolvePublicCred() in OmniRoute?
The resolvePublicCred() function ensures that public OAuth credentials can be embedded in the repository for development convenience while allowing secure override through environment variables in production. It checks the specified environment variable first, then falls back to a hard-coded default, maintaining compliance with the project's Hard Rule #11 security requirement.
Where should I store the default OAuth client credentials?
Default credentials must be stored within the resolvePublicCred() function calls inside src/lib/oauth/constants/oauth.ts. Never hard-code secrets directly into provider objects; always wrap them using resolvePublicCred("key", "ENV_VAR_NAME") to ensure they follow the security pattern defined in docs/security/PUBLIC_CREDS.md.
Do I need to modify the OAuth service layer for every new provider?
No. The service layer in src/lib/oauth/providers.ts automatically discovers new providers through the barrel export in src/lib/oauth/providers/index.ts. You only need to modify the service layer if the provider requires a custom authentication flow that deviates from standard OAuth 2.0 specifications.
How do I override the default credentials in production?
Set the corresponding environment variables defined in the second parameter of resolvePublicCred() (e.g., MYPROVIDER_OAUTH_CLIENT_ID). The utility function checks for these environment variables at runtime before falling back to the embedded defaults, allowing secure credential injection without code changes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →