Skip to main content

Authentication

Every Rise Public API request carries an OAuth 2.0 bearer token in the Authorization header. This page walks through registering an application, choosing a grant type, and obtaining + refreshing tokens.

Choosing a grant type​

Use caseFlow
Server-to-server, no user interaction (your backend → Rise)Client Credentials
Acting on behalf of a signed-in Rise user (partner app, public client)Authorization Code with PKCE
Refreshing an expired user access tokenRefresh token

Device flow, implicit flow, and password grant are not supported.

Registering an application​

  1. Sign in to your Rise account as an account owner or administrator.
  2. Go to People → Settings → OAuth applications.
  3. Click Create application and fill in:
    • Name — shown to users on the consent screen
    • Redirect URI(s) — for Authorization Code flow; must be https:// (except http://localhost in development)
    • Scopes — see Scope reference below
  4. Choose client type:
    • Confidential — server-to-server; issues a client_id + client_secret
    • Public — browser or mobile; issues client_id only, requires PKCE

You'll receive the client_id (and client_secret if confidential) immediately. The secret is shown once — store it somewhere safe.

Client Credentials​

Use this when your own backend is the caller and no end user is involved.

curl -X POST https://api.risepeople.com/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$RISE_CLIENT_ID" \
-d "client_secret=$RISE_CLIENT_SECRET" \
-d "scope=reports:read user:read"

Response:

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "reports:read user:read"
}

Cache the token for expires_in seconds (currently 1 hour); request a new one before it expires.

Authorization Code with PKCE​

Use this when a human is involved — your app acts on behalf of a Rise user who has explicitly granted you permission.

Step 1 — generate a PKCE verifier + challenge​

The code verifier is a high-entropy random string; the challenge is its SHA-256 hash, base64url-encoded.

import crypto from "node:crypto";

const verifier = crypto.randomBytes(32).toString("base64url");
const challenge = crypto.createHash("sha256").update(verifier).digest("base64url");

Store the verifier server-side (or in session storage) keyed by a state value you'll send to Rise.

Step 2 — redirect the user to /oauth/authorize​

https://api.risepeople.com/v1/oauth/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https%3A%2F%2Fyour-app.example.com%2Fcallback
&scope=reports%3Aread%20user%3Aread
&state=OPAQUE_ANTI_CSRF_VALUE
&code_challenge=CHALLENGE_FROM_STEP_1
&code_challenge_method=S256

Rise shows a consent screen; if the user approves, they're redirected to your redirect_uri with ?code=...&state=....

Step 3 — exchange the code for tokens​

curl -X POST https://api.risepeople.com/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=$CODE_FROM_CALLBACK" \
-d "redirect_uri=https://your-app.example.com/callback" \
-d "client_id=$RISE_CLIENT_ID" \
-d "code_verifier=$VERIFIER_FROM_STEP_1"

Response:

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "def50200...",
"scope": "reports:read user:read"
}

Refreshing a token​

When an access token expires (401 token_expired), exchange the refresh token for a new one:

curl -X POST https://api.risepeople.com/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=$REFRESH_TOKEN" \
-d "client_id=$RISE_CLIENT_ID"

Refresh tokens rotate: the response contains a new refresh_token. Discard the old one — using it again returns 401.

Using the token​

Pass the access token in the Authorization header on every call:

curl https://api.risepeople.com/v1/employees/42 \
-H "Authorization: Bearer $ACCESS_TOKEN"

Scope reference​

ScopeGrants
reports:readList, retrieve, and run reports
reports:writeCreate, update, and delete saved report configurations
user:readRead the authenticated user's OpenID profile information
user:writeUpdate the authenticated user's OpenID profile information

A valid token without the right scope returns 403 insufficient_scope, not 401 — check the error response to distinguish authentication ("we don't know who you are") from authorization ("we know who you are, but you can't do this") failures.

Token lifetime​

TokenLifetime
Access token (Client Credentials)1 hour
Access token (Authorization Code)1 hour
Refresh token30 days, rotated on every use

Revoking a token​

curl -X POST https://api.risepeople.com/v1/oauth/revoke \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=$ACCESS_OR_REFRESH_TOKEN" \
-d "client_id=$RISE_CLIENT_ID" \
-d "client_secret=$RISE_CLIENT_SECRET" # omit for public clients

Revoking a refresh token also revokes all access tokens derived from it.

Common errors​

HTTPtypeMeaning
400invalid_requestMissing or malformed parameter
401invalid_clientclient_id / client_secret wrong
401invalid_grantCode expired, already used, or PKCE verifier mismatch
401token_expiredAccess token past expires_in — refresh it
403insufficient_scopeValid token but missing the scope for this endpoint

See Errors for the full problem-details envelope.