This guide is for developers integrating Login with Prosper into a third-party app. Prosper acts as the OAuth 2.0 identity provider: your app sends users to Prosper to sign in, and Prosper returns a short-lived access token you can use to read the signed-in user's profile.
If you've integrated Login with Google or Sign in with Apple, this is the same shape — an Authorization Code grant, a server-to-server token exchange, and bearer tokens on the wire.
client_id and client_secret from us — see Get your credentials.In this article
- 1. Get your credentials
- 2. How the flow works
- 3. Environment
- 4. Endpoint reference
- 5. Production checklist
- 6. Common errors
- 7. Limits & gotchas
- 8. Get help
1. Get your credentials
Email support@prosperex.com.au to register your application. Include:
- Application name — shown to users on the consent screen (for example, "Acme HR").
- Application URL — your product's homepage.
- Redirect URIs — every URL Prosper is allowed to redirect users back to after sign-in. Exact match is enforced on path, host, and scheme — adding a query string at runtime is fine.
- Logo (optional) — shown on the consent screen.
You'll receive:
-
client_id— public; embedded in your app's redirect URLs. -
client_secret— secret; server-side only.
client_secret like a password. Never ship it to a browser or a mobile app.2. How the flow works
The diagram below shows the full round trip, from the user clicking the button to your app setting its own session.
┌─────────┐ ┌─────────────────┐ ┌─────────┐
│ Browser │ │ Your app server │ │ Prosper │
└────┬────┘ └────────┬────────┘ └────┬────┘
│ │ │
│ 1. Click "Login with Prosper" │ │
│ ──────────────────────────────────►│ │
│ 2. 302 → Prosper /authorize?client_id=…&redirect_uri=…&state=… │
│ ◄────────────────────────────────────────────────────────────────►│
│ 3. User signs in to Prosper + approves consent │
│ ─────────────────────────────────────────────────────────────────►│
│ 4. 302 → your redirect_uri?code=<one-time-code>&state=… │
│ ◄─────────────────────────────────────────────────────────────────│
│ 5. GET /auth/prosper?code=… │ │
│ ──────────────────────────────────►│ 6. POST /access-token │
│ │ {client_id, secret, code} │
│ │ ────────────────────────────►│
│ │ 7. { access_token, … } │
│ │ ◄────────────────────────────│
│ │ 8. GET /api/v2/user │
│ │ Authorization: Bearer … │
│ │ ────────────────────────────►│
│ │ 9. { uid, email, … } │
│ │ ◄────────────────────────────│
│ 10. You set your own session/cookie │
│ ◄──────────────────────────────────│ │Key properties:
- The user's password never touches your server — they sign in on Prosper.
- The
codeis single-use and short-lived (5 minutes). It's encrypted and useless without yourclient_secret. - The
access_tokenis bearer-style and short-lived (15 minutes). There is no refresh token in this flow — re-run the authorize step to get a new one.
3. Environment
| Environment | Base URL |
|---|---|
| Production | https://admin-prod.prosperex.com.au |
All endpoints below are relative to this base URL.
4. Endpoint reference
4.1 Authorize — GET /login/oauth/authorize
Send the user's browser here to start sign-in.
Query parameters
| Name | Required | Notes |
|---|---|---|
client_id |
Yes | Your registered client id. |
redirect_uri |
Yes | Must exactly match one of your registered redirect URIs. |
scope |
Yes | Must be user:email (the only scope supported today). |
state |
Recommended | An opaque value you generate; Prosper echoes it back on the redirect. Use it to bind the response to the user's session and to prevent CSRF. |
Behaviour
- If the user is not signed in to Prosper, they're sent to the Prosper login page, then back through this flow.
- If the user hasn't yet consented to your app, they see a consent screen, then are redirected to your
redirect_uriwith acode. - If they've already consented, they're redirected immediately to your
redirect_uriwith acode.
On success, Prosper redirects (302) the browser to:
<your redirect_uri>?code=<one-time-code>&state=<your state>
4.2 Token — POST /login/oauth/access-token
Swap the one-time code for an access token.
client_secret.Headers: Content-Type: application/json (or application/x-www-form-urlencoded — both are accepted)
Request body
{
"client_id": "your-client-id",
"client_secret": "your-client-secret",
"code": "the-code-you-received"
}Success response — 200
{
"access_token": "…opaque base64 blob…",
"token_type": "bearer",
"scope": "user:email",
"expires_in": 900
}expires_in is in seconds (15 minutes). The token is opaque — don't try to decode it; only Prosper can.
Failure responses — 400
| Body | Meaning |
|---|---|
"Invalid code" |
The code couldn't be decrypted, or has already been used. |
"Code has expired" |
More than 5 minutes passed between authorize and token exchange. |
"Invalid client id" |
The code wasn't issued for the client_id you sent. |
"Client not found" |
No application is registered with that client_id. |
"Invalid secret" |
The client_secret doesn't match. |
4.3 User — GET /api/v2/user
Read the signed-in user's profile.
Headers: Authorization: Bearer <access_token>
Success response — 200
{
"uid": "9f3a…-…-…",
"id": 12345,
"login": "alice@acme.com",
"email": "alice@acme.com",
"firstName": "Alice",
"lastName": "Smith",
"userName": "alice@acme.com"
}| Field | Notes |
|---|---|
uid |
Stable GUID that identifies the member. |
id |
Internal numeric id. Stable, but Prosper-internal. |
email |
The member's email on Prosper. |
login |
Usually the email. |
userName |
Same value as login. |
firstName / lastName
|
Derived from the member's full name (split on the first/last space). |
This is the only resource endpoint exposed under the social-login scope today.
5. Production checklist
-
Keep
client_secreton the server only. Never in JS bundles, mobile binaries, repo files, or URLs. -
Validate
stateon the redirect. Generate it cryptographically, store it bound to the user's session, and reject anything that doesn't match. - Use real TLS. Always verify Prosper's certificate — it's your only defence against MITM. Don't disable certificate validation.
-
Field stability.
uidandidare stable;emailcan change. Worth keeping in mind when deciding how to match users to your own records. -
Handle the 15-minute token window. Treat the access token as one-shot: read the profile, create your own session, then discard the token. There is no refresh — to re-read the profile later, send the user through
/authorizeagain.
6. Common errors
| Symptom | Cause |
|---|---|
| User is redirected to Prosper's welcome page instead of your app. |
client_id not recognised, or redirect_uri isn't an exact match. |
Authorize succeeds, but the token call returns "Invalid code". |
The code was already used, or you started a second token call before the first finished. Codes are strictly single-use. |
Token call returns "Code has expired". |
More than 5 minutes elapsed between the authorize redirect and your token call. |
User completes sign-in but is bounced to /welcome. |
The user belongs to a different Prosper space than your OAuth application. Each application is bound to one space. |
/api/v2/user returns 401 / "Invalid token". |
The token expired (15 min) or is malformed. Re-run the authorize flow. |
7. Limits & gotchas
-
Scope: only
user:emailis supported. Other scopes are rejected. - Refresh tokens: not issued. Re-authorize to extend a session.
- Token lifetime: 15 minutes from issue.
- Code lifetime: 5 minutes from issue, single use.
- One application = one Prosper space. To support users across multiple tenants, you'll need multiple applications.
-
Confidential clients only (no PKCE). This flow assumes you have a backend that can hold
client_secret. Pure SPA / native-mobile-without-backend flows aren't supported.
8. Get help
- Get credentials / register an application: support@prosperex.com.au
- Bug reports / questions about this guide: support@prosperex.com.au
When reporting an issue, include your client_id (never the secret) and the environment you're hitting.
Comments
0 comments
Please sign in to leave a comment.