e-Próspera

OAuth 2.0 / OpenID Connect

e-Próspera provides an OAuth 2.0 and OpenID Connect authorization server so third-party applications can authenticate users and access their data with consent.

View as Markdown

Capabilities

  • Authenticate users with their e-Próspera account
  • Receive standard OIDC claims (sub, name, email, picture)
  • Obtain refresh tokens for long-lived server access via offline_access
  • Fetch user-authorized personal and legal-entity data through the /api/v1/me/* endpoints
  • Read personal or consented-entity tax obligations and submitted filings

Getting credentials

OAuth clients are provisioned per account. If you already have one, you can view the client ID, allowed scopes, and redirect URIs in Developer → OAuth application.

To request a new client or have your secret re-issued, use the e-Próspera Help Center chat.

Redirect URI requirements

Register every callback URI in full, including its scheme, host, port, path, and query string. Authorization requests use exact string matching: a URI that differs only by host capitalization, an explicit default port, or a trailing slash is still a different URI.

  • Production callbacks must use HTTPS.
  • Staging and local-development clients may use HTTP only with 127.0.0.1, [::1], or localhost.
  • Prefer 127.0.0.1 or [::1] for new local integrations. localhost remains supported for compatibility.
  • Credentials, fragments, and raw semicolons are not permitted.
  • Ports are matched exactly.

Testing a callback locally

Use a separately provisioned staging OAuth client and register the exact loopback callback your local application listens on, for example http://127.0.0.1:3001/auth/oauth2/callback/prospera. Start the flow through https://staging-portal.eprospera.com; the production authorization server rejects HTTP callbacks, including loopback addresses. See Testing in staging for the complete setup.

Older stored callbacks may remain visible while you edit a client. They can be removed, but they are not automatically rewritten and cannot be duplicated if they no longer satisfy the current registration policy. A grandfathered HTTP callback is never accepted by the production authorization endpoint.

Standard endpoints

EndpointURL
OpenID configurationhttps://portal.eprospera.com/.well-known/openid-configuration
JWKShttps://portal.eprospera.com/api/oauth/.well-known/jwks.json
Authorization endpointhttps://portal.eprospera.com/api/oauth/authorize
Device endpointhttps://portal.eprospera.com/api/oauth/device_authorization
Token endpointhttps://portal.eprospera.com/api/oauth/token
UserInfo endpointhttps://portal.eprospera.com/api/oauth/userinfo
Revocation endpointhttps://portal.eprospera.com/api/oauth/revoke
Introspection endpointhttps://portal.eprospera.com/api/oauth/introspect

Reference pages:

Start with:

openid profile email

Add offline_access if your backend needs refresh tokens.

Supported scopes

ScopeDescription
openidAuthenticate the user with e-Próspera.
profileRead the user's name and profile picture.
emailRead the user's email address.
offline_accessReceive a refresh token for background access-token renewal.
eprospera:person.details.readRead detailed natural-person profile data.
eprospera:person.residency.readRead the user's current residency status.
eprospera:person.id_verification.readRead the latest approved identity-verification images.
eprospera:entity.readRead legal-entity data for entities the user consents to share.
eprospera:entity.documents.readRead legal-entity documents for consented entities.
eprospera:person.tax.readRead the user's tax obligations and submitted filings.
eprospera:entity.tax.readRead tax data for consented legal entities.

When you request entity scopes (eprospera:entity.read, eprospera:entity.documents.read, or eprospera:entity.tax.read), the consent screen lets the user choose which legal entities to share. The access token is limited to that selection.

This means:

  • GET /api/v1/me/legal-entities can return an empty array even with a valid token.
  • GET /api/v1/me/legal-entities/{id} and /documents only work for consented entity IDs.
  • If the user is no longer a representative of an entity, it stops appearing in responses.

Once a user approves your client, the grant is remembered. Later authorization requests covered by the remembered grant skip the consent screen — the user is redirected straight back to your redirect_uri with a fresh authorization code. Requests for additional scopes show the consent screen again, and you can always force it with prompt=consent.

Revocation from Connected apps

Users can revoke your app's access at any time from portal Settings → Connected apps. Revocation invalidates all of your tokens for that user: access tokens stop working, and refresh attempts fail with invalid_grant. Handle invalid_grant by sending the user back through the authorization flow.

PKCE

All newly registered clients must use PKCE: send code_challenge + code_challenge_method=S256 on the authorization request and the matching code_verifier on the token exchange. Authorization requests from PKCE-required clients without a code challenge fail with error=invalid_request. Existing clients without the flag should adopt PKCE too — it is strongly recommended for every integration.

Client secret rotation

You can request a rotation of your client secret at any time through the e-Próspera Help Center chat. After a rotation, the old secret keeps working during a grace period so you can deploy without downtime — update your integration to the new secret before the grace period expires.

Resource endpoints

For an end-to-end explanation of user and entity selection, CLI examples, and sensitive-data handling, see Tax and legal-entity data.

The scopes above unlock these endpoints:

EndpointRequired scope
GET /api/v1/me/natural-personeprospera:person.details.read
GET /api/v1/me/natural-person/residencyeprospera:person.residency.read
GET /api/v1/me/natural-person/id-verificationeprospera:person.id_verification.read
GET /api/v1/me/legal-entitieseprospera:entity.read
GET /api/v1/me/legal-entities/{id}eprospera:entity.read
GET /api/v1/me/legal-entities/{id}/documentseprospera:entity.documents.read
GET /api/v1/me/tax/summarypersonal or entity tax read
GET /api/v1/me/tax/filingspersonal or entity tax read
GET /api/v1/me/tax/filings/{filingId}personal or entity tax read
GET /api/v1/me/tax/filings/{filingId}/documents/{document}personal or entity tax read

/api/v1/me/natural-person/id_verification (underscore) exists as a compatibility alias. Use /id-verification (hyphen) for new integrations.

Authorization flow

  • response_type=code is required.
  • state is required.
  • nonce is required when openid is in scope.
  • response_mode is optional (query, fragment, or form_post; default query).
  • prompt, max_age, and login_hint are supported — see the authorization endpoint reference.
  • Every authorization response includes the iss parameter (RFC 9207); validate it against https://portal.eprospera.com.
  • Unauthenticated users are redirected to the portal login before returning to the authorization request.
  • Repeat the registered redirect_uri exactly during the authorization-code exchange.

Client authentication and request encoding

Send token, revocation, and introspection requests as application/x-www-form-urlencoded. HTTP Basic authentication is recommended:

curl -X POST https://portal.eprospera.com/api/oauth/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=$CODE" \
  -d "redirect_uri=$REDIRECT_URI" \
  -d "code_verifier=$CODE_VERIFIER"

client_secret_post remains available for compatibility. Do not combine Basic authentication with body credentials, and do not repeat OAuth parameters.

The official CLI is a registered public client. Its device-token and revocation requests send the client ID without a client secret. This secretless public-client mode is reserved for the official CLI; third-party clients should use their provisioned authentication method and the authorization-code flow with PKCE.

Device authorization for the official CLI

The official eprospera CLI is a public OAuth client and uses the device flow, so it never embeds a client secret. Start it with:

eprospera auth login --oauth

The CLI displays a short code and opens the portal consent page. It polls the token endpoint at the server-provided interval, handles authorization_pending and slow_down, and stores the resulting rotating refresh token securely. This flow is currently reserved for the official CLI; third-party OAuth clients use the authorization-code flow with PKCE.

Refresh tokens

Access tokens expire after 1 hour.

If the granted scope set includes offline_access, the token response also includes a refresh_token valid for up to 180 days.

Example refresh request:

curl -X POST https://portal.eprospera.com/api/oauth/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=$REFRESH_TOKEN"

Refresh tokens rotate on every successful refresh. Always persist the newest refresh_token from the response. You may request a reduced scope set on refresh, provided it is a subset of the originally granted scopes. When openid is granted, the refresh response also includes a fresh id_token whose auth_time remains the time of the user's original authentication. Reusing an already rotated refresh token revokes its token family; restart the authorization flow after invalid_grant.

Bearer-token errors

Protected endpoints return a WWW-Authenticate: Bearer challenge for missing or invalid access tokens. A valid token without the required scope returns 403 with error="insufficient_scope". The UserInfo endpoint supports both GET and POST.

Framework guides

On this page