How pushedAuthorizationRequests Works with buildAuthorizationUrl in Auth0 Auth-JS
When you pass { pushedAuthorizationRequests: true } to AuthClient.buildAuthorizationUrl(), the SDK initiates a Pushed Authorization Request (PAR) flow by posting parameters to the tenant's pushed_authorization_request_endpoint and returns an authorization URL containing only a request_uri instead of the full parameter set.
The Auth0 Auth-JS library provides built-in support for OAuth 2.0 Pushed Authorization Requests to help applications avoid URL length limitations and prevent sensitive authorization parameters from appearing in browser history. By enabling the pushedAuthorizationRequests option when calling buildAuthorizationUrl(), you activate a secure backend-channel approach that validates tenant capabilities before constructing the final redirect URL. This implementation is located in the AuthClient class within the auth0/auth0-auth-js repository.
How PAR Integrates with buildAuthorizationUrl
The integration follows a strict three-step validation and execution path defined in packages/auth0-auth-js/src/auth-client.ts.
Step 1: Server Metadata Discovery
First, the SDK discovers whether the tenant supports PAR. The private #discover() method fetches the OpenID Connect configuration from https://<domain>/.well-known/openid-configuration and examines the resulting serverMetadata for the presence of pushed_authorization_request_endpoint.
const { serverMetadata } = await this.#discover();
According to the source code at lines 69-73 of auth-client.ts, this discovery happens immediately upon entering the public buildAuthorizationUrl() method, ensuring the SDK has current tenant capabilities before proceeding.
Step 2: PAR Capability Validation
Before constructing the URL, the SDK validates that PAR is actually available. At lines 72-76 of auth-client.ts, the code checks if options?.pushedAuthorizationRequests is true while the serverMetadata lacks the required endpoint.
if (options?.pushedAuthorizationRequests && !serverMetadata.pushed_authorization_request_endpoint) {
throw new NotSupportedError(
NotSupportedErrorCode.PAR_NOT_SUPPORTED,
'The Auth0 tenant does not have pushed authorization requests enabled. Learn how to enable it here: https://auth0.com/docs/get-started/applications/configure-par'
);
}
The NotSupportedError with code PAR_NOT_SUPPORTED is defined in packages/auth0-auth-js/src/errors.ts. This guard prevents runtime failures against tenants that have not explicitly enabled the PAR feature in their Auth0 dashboard.
Step 3: Conditional URL Construction
After passing the validation guard, the private #buildAuthorizationUrl() method prepares PKCE parameters and selects the appropriate builder. At lines 81-84 of auth-client.ts, the SDK conditionally invokes either the standard or PAR-specific helper from the internal client module.
const authorizationUrl = options?.pushedAuthorizationRequests
? await client.buildAuthorizationUrlWithPAR(configuration, params) // PAR path
: await client.buildAuthorizationUrl(configuration, params); // Classic path
buildAuthorizationUrlWithPAR performs three operations:
- POSTs the merged authorization parameters (including
client_id,code_challenge, and customauthorizationParams) to thepushed_authorization_request_endpoint. - Receives a JSON response containing a
request_uri(e.g.,urn:example:request_uri_123). - Assembles the final
/authorizeURL containing onlyclient_idandrequest_uriquery parameters, significantly reducing URL length and keeping sensitive data out of the browser's address bar.
Implementation Details in auth-client.ts
The complete flow demonstrates how the SDK handles parameter preparation before the conditional PAR call. The method first generates PKCE values using client.randomPKCECodeVerifier() and client.calculatePKCECodeChallenge(), then merges default and user-supplied parameters using stripUndefinedProperties from packages/auth0-auth-js/src/utils.ts.
const codeVerifier = client.randomPKCECodeVerifier();
const codeChallenge = await client.calculatePKCECodeChallenge(codeVerifier);
const additionalParams = stripUndefinedProperties({
...this.#options.authorizationParams,
...options?.authorizationParams,
});
const params = new URLSearchParams({
scope: DEFAULT_SCOPES,
...additionalParams,
client_id: this.#options.clientId,
code_challenge: codeChallenge,
code_challenge_method: 'S256',
});
These parameters are passed to either buildAuthorizationUrlWithPAR or buildAuthorizationUrl depending on the pushedAuthorizationRequests boolean. The PKCE generation occurs regardless of which path is taken, ensuring consistent security across both flows.
Code Examples
Standard Authorization URL (Classic Flow)
For tenants without PAR enabled, or when you prefer the traditional approach, omit the pushedAuthorizationRequests option.
import { AuthClient } from '@auth0/auth0-auth-js';
const client = new AuthClient({
domain: 'my-tenant.auth0.com',
clientId: '<client_id>',
clientSecret: '<client_secret>',
});
const { authorizationUrl, codeVerifier } = await client.buildAuthorizationUrl({
authorizationParams: {
redirect_uri: 'https://myapp.com/callback'
}
});
// Redirect user to authorizationUrl.href
PAR-Enabled Authorization URL
Enable the Pushed Authorization Request flow by setting pushedAuthorizationRequests: true. The resulting URL will contain only the request_uri parameter.
import { AuthClient } from '@auth0/auth0-auth-js';
const client = new AuthClient({
domain: 'my-tenant.auth0.com',
clientId: '<client_id>',
clientSecret: '<client_secret>',
});
const { authorizationUrl, codeVerifier } = await client.buildAuthorizationUrl({
pushedAuthorizationRequests: true, // Enable PAR
authorizationParams: {
redirect_uri: 'https://myapp.com/callback',
audience: 'https://api.example.com'
}
});
// authorizationUrl.searchParams.get('request_uri') contains the reference
// authorizationUrl.searchParams.size is minimal (typically 2)
Handling Tenants Without PAR Support
The SDK throws a specific error code when PAR is requested but not available. Catch NotSupportedError with code par_not_supported_error to implement fallback logic.
import { NotSupportedError } from '@auth0/auth0-auth-js';
try {
const { authorizationUrl } = await client.buildAuthorizationUrl({
pushedAuthorizationRequests: true
});
} catch (err) {
if (err instanceof NotSupportedError && err.code === 'par_not_supported_error') {
// Fallback to classic flow
const { authorizationUrl } = await client.buildAuthorizationUrl();
// Proceed with standard authorization
}
}
The test suite in packages/auth0-auth-js/src/auth-client.spec.ts validates this behavior. Lines 658-662 verify that deleting pushed_authorization_request_endpoint from the mock discovery document causes buildAuthorizationUrl({ pushedAuthorizationRequests: true }) to throw the specific error message. Conversely, lines 687-706 confirm that when the endpoint is present, the resulting URL contains only the request_uri parameter with a minimal query string size of 2.
Summary
- Discovery First: The SDK always fetches fresh metadata from
/.well-known/openid-configurationto check forpushed_authorization_request_endpointbefore attempting PAR. - Strict Validation: If
pushedAuthorizationRequests: trueis passed but the tenant lacks support, the SDK immediately throwsNotSupportedErrorwith codePAR_NOT_SUPPORTEDfromauth-client.tslines 72-76. - Backend Channel: The
buildAuthorizationUrlWithPARhelper posts full parameter sets to the PAR endpoint, receiving arequest_urithat replaces the bulky query string in the final authorization URL. - PKCE Compatible: PAR flows in Auth0 Auth-JS always include PKCE generation (
code_challengeandcode_verifier) regardless of whether the classic or PAR path is taken. - Minimal URLs: The final authorization URL contains only
client_idandrequest_uri, mitigating browser URL length limits and preventing sensitive parameters from appearing in browser history.
Frequently Asked Questions
What happens if I request PAR on a tenant that does not support it?
The SDK throws a NotSupportedError with the error code par_not_supported_error. According to the implementation in auth-client.ts lines 72-76, this check occurs after fetching the discovery document but before making any PAR HTTP requests, ensuring clear failure messaging that directs you to Auth0's PAR configuration documentation.
Can I use PAR with PKCE in Auth0 Auth-JS?
Yes. The SDK automatically generates PKCE code verifiers and challenges for all authorization flows, including PAR. As shown in the source code, client.randomPKCECodeVerifier() and client.calculatePKCECodeChallenge() execute before the conditional logic that selects between buildAuthorizationUrl and buildAuthorizationUrlWithPAR, ensuring the code_challenge is included in the parameters pushed to the PAR endpoint.
How does the final authorization URL differ when using pushedAuthorizationRequests?
Instead of containing all authorization parameters (scope, redirect_uri, audience, etc.) in the query string, the PAR-enabled URL contains only two parameters: client_id and request_uri. The request_uri value (e.g., urn:auth0:request:xyz123) is a reference handle that the authorization server uses to retrieve the full parameter set that was previously pushed via the backend POST request.
Where is the PAR error code defined?
The PAR_NOT_SUPPORTED error code is defined in packages/auth0-auth-js/src/errors.ts as part of the NotSupportedErrorCode enumeration. When thrown from auth-client.ts, the error includes a descriptive message explaining that the tenant does not have pushed authorization requests enabled and provides a link to the Auth0 documentation for configuring the feature.
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 →