hi, right now i have integrated auth using PKCE <h...
# ask-a-descoper
a
hi, right now i have integrated auth using PKCE https://docs.descope.com/getting-started/oidc-endpoints#using-pkce-in-your-endpoints i need to create federated app in descope for different env(dev/stag/QA) and project (CPE/CPC) but it is very difficult to manage right now and increases avoidable cost, how can i create federated app on the basis of origin to seperate the different env or project example qamfecpe/devmfecpe/stagmfecpe/qamfecpc/devmfecpc/stagmfecpc authorize url is created using this component first in angular app import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { environment } from '../../environments/environment'; @Component({ selector: 'app-gateway', standalone: true, template:
Copy code
<div style="text-align: center; margin-top: 50px; font-family: sans-serif;">
      <h2>Redirecting to secure login...</h2>
      <div class="loader"></div>
    </div>
, styles: [
.loader { border: 4px solid #F3F3F3; border-top: 4px solid #3498DB; border-radius: 50%; width: 30px; height: 30px; animation: spin 2s linear infinite; margin: 20px auto; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
] }) export class GatewayComponent implements OnInit { constructor(private route: ActivatedRoute, private router: Router) {} async ngOnInit() { const params = this.route.snapshot.queryParamMap; // 2. Identify Flow Intent (The Initial Landing) const customerId = params.get('customer_id'); const email = params.get('email'); const firstName = params.get('first_name'); const lastName = params.get('last_name'); // Logic: If user data exists in URL, it's a Signup flow const flowType = (firstName && customerId) ? 'signup' : 'login'; // Store data for the final BYOS component if (customerId) sessionStorage.setItem('signup_customer_id', customerId); if (email) sessionStorage.setItem('signup_email', email); if (firstName && lastName) sessionStorage.setItem('signup_name',
${firstName} ${lastName}
); // 3. Generate PKCE & State const codeVerifier = this.generateCodeVerifier(); const codeChallenge = await this.generateCodeChallenge(codeVerifier); // We prepend the flowType to the state so we know where to go on return const randomState = this.generateState(); const combinedState = `${flowType}_${randomState}`; sessionStorage.setItem('pkce_code_verifier', codeVerifier); sessionStorage.setItem('pkce_state', combinedState); const redirectUri = flowType === 'signup' ?
${window.location.origin}/exchange-token
: `${window.location.origin}/login-exchange-token`; // 4. Redirect to OIDC Authorize const authUrl = new URL(environment.descopeSignupAuthUrl); authUrl.searchParams.append('client_id', environment.descopeProjectId); // Redirect BACK to this same component (root '/') authUrl.searchParams.append('redirect_uri', redirectUri); authUrl.searchParams.append('response_type', 'code'); authUrl.searchParams.append('scope', 'openid profile email'); authUrl.searchParams.append('code_challenge', codeChallenge); authUrl.searchParams.append('code_challenge_method', 'S256'); authUrl.searchParams.append('state', combinedState); window.location.href = authUrl.toString(); } // --- PKCE Helpers --- private generateCodeVerifier(): string { const array = new Uint8Array(32); crypto.getRandomValues(array); return this.base64UrlEncode(array); } private async generateCodeChallenge(verifier: string): Promise<string> { const encoder = new TextEncoder(); const data = encoder.encode(verifier); const hash = await crypto.subtle.digest('SHA-256', data); return this.base64UrlEncode(new Uint8Array(hash)); } private base64UrlEncode(array: Uint8Array): string { return btoa(String.fromCharCode(...array)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); } private generateState(): string { const array = new Uint8Array(16); crypto.getRandomValues(array); return this.base64UrlEncode(array); } } then it goes to escope where need to define hosted url example http://localhost:4200/auth?flow=direct-signup-signin-flow-dev then goes to this component import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; @Component({ selector: 'app-oidc-flow-host', standalone: true, template:
Copy code
<div style="text-align: center; margin-top: 50px; font-family: sans-serif;">
      <p>Loading your custom experience...</p>
      <div class="spinner"></div>
    </div>
, styles: [
Copy code
.spinner { border: 4px solid #F3F3F3; border-top: 4px solid #3498DB; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite; margin: 20px auto; }
    @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
] }) export class OidcFlowHostComponent implements OnInit { constructor(private route: ActivatedRoute, private router: Router) {} ngOnInit() { // 1. Get the OIDC parameters Descope just sent to /auth const oidcParams = this.route.snapshot.queryParams; // 2. Retrieve the intent we saved in GatewayComponent const savedState = sessionStorage.getItem('pkce_state'); // 3. Determine if we go to Signup or Login let targetPath = '/auth/login'; // Default if (savedState && savedState.startsWith('signup')) { targetPath = '/signup'; } // 4. Redirect to the actual UI component, passing along all OIDC parameters // This is crucial so that the Descope SDK in those components knows // it's part of an active OIDC transaction. this.router.navigate([targetPath], { queryParams: oidcParams, queryParamsHandling: 'merge' // Keeps existing OIDC params in the URL }); } } how can this be achieved from descope
✅ 1
d
Hi, I'm Descope's AI assistant. I've put together an initial response below based on your question. Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits. For further assistance, you can visit Support.
a
?
a
Hi @Aksha Malik You don't need a separate federated app per environment. This is how you can solve this cleanly: The core fix — One Federated App, Multiple Redirect URIs Your Angular code is already doing the right thing by dynamically building the
redirect_uri
from `window.location.origin`:
Copy code
const redirectUri = flowType === 'signup'
  ? `${window.location.origin}/exchange-token`
  : `${window.location.origin}/login-exchange-token`;
In Descope, a single federated app accepts a list of allowed redirect URIs. You just need to register all your environment URLs in that one app: •
<https://devmfecpe.yourdomain.com/exchange-token>
•
<https://devmfecpe.yourdomain.com/login-exchange-token>
•
<https://stagmfecpe.yourdomain.com/exchange-token>
•
<https://stagmfecpe.yourdomain.com/login-exchange-token>
•
<https://qamfecpe.yourdomain.com/exchange-token>
•
<https://qamfecpe.yourdomain.com/login-exchange-token>
Descope will validate the
redirect_uri
in the request against this whitelist — one app handles all envs. Since CPE and CPC are different products with separate user bases, I'd recommend 2 Descope projects (one per product). Within each project: • 1 federated app covering all 3 envs via the multi-redirect-URI approach above • Use Descope's project clone feature to copy your CPE config into CPC, then adjust as needed — this keeps them in sync without manual duplication For the hosted flow URL per environment In each Angular environment file, set
descopeSignupAuthUrl
to your Descope OIDC authorize endpoint with the right
flow
param:
Copy code
// environment.dev.ts
export const environment = {
  descopeSignupAuthUrl: '<https://api.descope.com/oauth2/v1/authorize>',
  descopeProjectId: 'YOUR_PROJECT_ID',
  flowId: 'direct-signup-signin-flow-dev'  // env-specific flow
};
Then in
GatewayComponent
, append the flow to the auth URL:
Copy code
const authUrl = new URL(environment.descopeSignupAuthUrl);
authUrl.searchParams.append('flow_id', environment.flowId); // pass env-specific flow
This cuts your federated app count from 6 down to 2, with zero code changes to your PKCE logic. I hope this will help you to resolve your issue just let me know if this works!
a
Thanks a lot! I will check and let you know
a
Sure!
🙌 1
a
HI @Akash Jivane i have some queries regarding this. 1. how to whitelist all the redirect url, didnt find this option in side federated application 2. also how to manage different flow hosting urls which i need to set for different environments inside federated apps.
this is bit of urgent for me, can you please help me as soon as possible
a
Hi @Aksha Malik Sorry for the delay. 1. Where to whitelist redirect URIs This is not inside the federated app — it's at the project level: Descope Console → Project Settings → General → Security → Approved Domains Add all your environment domains there (e.g.
<http://devmfecpe.yourdomain.com|devmfecpe.yourdomain.com>
,
<http://stagmfecpe.yourdomain.com|stagmfecpe.yourdomain.com>
, etc.). Descope will allow any path under those domains as a valid redirect target. 2. Managing Flow Hosting URLs across environments
Copy code
Set the Flow Hosting URL in your federated app to Descope's hosted page:<https://auth.descope.io/><YOUR_PROJECT_ID>?flow=direct-signup-signin-flow-dev
This is environment-agnostic — auth runs on Descope's side, and after completion, users are redirected back to your Angular app via the dynamic
redirect_uri
your code already builds from
window.location.origin
. One app, no per-environment config needed. Let me know if this answers your questions!
a
but how will this work with my bring your own screen feature i need to work with. i use bring your own screen to show signup/login/forgot password screen
a
Since you're self-hosting the auth UI in Angular, here's the cleanest approach: Host your BYOS auth page at a single, stable URL (e.g.
<https://auth.cpe.yourdomain.com/auth>
) and set that as the Flow Hosting URL in your federated app. This page runs the Descope web component with your custom screens — it doesn't need to be env-specific since the screens are the same across dev/stag/QA. The env-specific part is already handled by
redirect_uri
in your PKCE code — after auth completes, Descope redirects the user back to whichever env triggered the flow (
devmfecpe
,
stagmfecpe
, etc.), all of which are whitelisted in Approved Domains. So the final setup would be : • 2 federated apps (one per project — CPE & CPC) • Flow Hosting URL = one stable shared auth page per project • Approved Domains = all env-specific domains whitelisted • BYOS screens work as usual on the shared auth page Does this setup work for you ?
a
can this flow hosting url be setup bsed upon window origin or in some way through configuration in descope, or this is the only approch?
a
No, the Flow Hosting URL in Descope is a static field and doesn't support dynamic values, wildcards, or origin-based routing out of the box. The shared stable URL approach is the cleanest single-app solution. That said, if you truly need each environment to serve the BYOS screens from its own origin (e.g.
<http://devmfecpe.yourdomain.com/auth|devmfecpe.yourdomain.com/auth>
), the only option in Descope is one federated app per environment — which is exactly the cost concern you started with. To keep it to 2 apps, the shared auth page approach is the way to go. One practical tip: you can still pass the originating env in the PKCE
state
parameter (you're already doing
flowType_randomState
), and your shared auth page can read that to apply any env-specific config (e.g. different branding or flow IDs) without needing separate hosted URLs. Hope that clears things up!
@Aksha Malik Is your issue is resolved now ?
a
need to check with my senior will let you know. thanks
a
Sure!
🙌 1