PSOhub API: OAuth 2.0 Quickstart Guide
Learn how to authenticate using OAuth 2.0 with the PSOhub API
Published: 1 June 2026
Audience
-
Admin
Objective
This article explains how to authenticate with the PSOhub API using the OAuth 2.0 Authorization Code grant type — including how to obtain an access token, make authenticated API calls, and refresh tokens when they expire.
Prerequisites
Eligible access
You must have Admin user access in PSOhub.
API access requested
You must have requested API access via hello@psohub.com.
Client ID and Client Secret
You must have created an app in the PSOhub developer portal to obtain your Client ID and Client Secret.
How OAuth 2.0 Works in PSOhub
PSOhub uses the OAuth 2.0 Authorization Code grant type. The flow involves four steps:
- Your application directs the user to the PSOhub OAuth 2.0 server
- The user reviews the requested permissions and grants access
- The user is redirected back to your application with an authorization code
- Your application exchanges the authorization code for an access token
Step 1: Direct the User to the PSOhub OAuth 2.0 Server
Build an authorization URL using the parameters below and redirect the user to it.
Authorization URL parameters
| Parameter | Required | Description | Example |
|---|---|---|---|
| clientid | Yes | Your app's Client ID, found in the developer portal app settings. | 7fff1e36-2d40-4ae1-bbb1-5266d59564fb |
| scope | Yes | The API scopes your app is requesting, separated by URL-encoded spaces. | projects%20timesheets |
| redirecturl | Yes | The URL the user is redirected to after authorizing your app. HTTPS is required for production. | https://www.example.com/auth-callback |
| clientsecret | Yes | Your app's Client Secret, found in the developer portal app settings. | 240b7951-2f4b-4d05-b278-8cfab90c7922 |
Example — server-side redirect
javascript
const authUrl = 'https://www.psohubapp.com/link/apiauthorization' + `?clientid=${encodeURIComponent(CLIENT_ID)}` + `&scope=${encodeURIComponent(SCOPES)}` + `&redirecturl=${encodeURIComponent(REDIRECT_URI)}`; return res.redirect(authUrl);
Example — HTML link
html
<a href="https://www.psohubapp.com/link/apiauthorization?scope=projects%20timesheets&redirecturl=https://www.example.com/auth-callback&clientid=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&clientsecret=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">Install</a>
Step 2: User Grants Consent
PSOhub displays a consent screen showing your app name and the permissions it is requesting. The user can then approve or deny access. Your application does not take any action at this stage.
Once the user grants access, the PSOhub OAuth 2.0 server sends a request to the callback URL defined in your authorization URL.
Step 3: Handle the OAuth 2.0 Server Response
After the user completes the consent step, the OAuth 2.0 server sends a GET request to your redirect URI with a code query parameter attached.
📌 Note: If the user denies access, no request is sent to your redirect URI.
Example — handling the authorization code
javascript
app.get('/oauth-callback', async (req, res) => { if (req.query.code) { // Handle the received code } });
Step 4: Exchange the Authorization Code for Tokens
Send a URL-form encoded POST request to exchange the authorization code for an access token and refresh token.
Endpoint
POST https://www.psohubapp.com/oauth/token
Request parameters
| Parameter | Description | Example |
|---|---|---|
| grant_type | Must be authorization_code. |
authorization_code |
| client_id | Your app's Client ID. | 7fff1e36-2d40-4ae1-bbb1-5266d59564fb |
| client_secret | Your app's Client Secret. | 7c3ce02c-0f0c-4c9f-9700-92440c9bdf2d |
| redirect_uri | The redirect URI used when the user authorized your app. | https://www.example.com/auth-callback |
| authorization_code | The authorization code received from the OAuth 2.0 server. | 5771f587-2fe7-40e8-8784-042fb4bc2c31 |
Example request
javascript
const formData = { grant_type: 'authorization_code', client_id: CLIENT_ID, client_secret: CLIENT_SECRET, redirect_uri: REDIRECT_URI, code: req.query.code }; request.post('https://www.psohubapp.com/oauth/token', { form: formData }, (err, data) => { // Handle the returned tokens });
Example response
json
{ "refresh_token": "6f18f21e-a743-4509-b7fd-1a5e632fffa1", "access_token": "CN2zlYnmLBICAQIYgZXFLyCWp1Yoy_9GMhkAgddk-zDc-H_rOad1X2s6Qv3fmG1spSY0Og0ACgJBAAADAIADAAABQhkAgddk-03q2qdkwdXbYWCoB9g3LA97OJ9I", "expires_in": 600 }
📌 Note: The default access token expiration time is 10 minutes, returned as 600 seconds in the expires_in field.
How to Use Your Access Token
Once you have an access token, include it as a bearer token in the Authorization header of all API requests.
Example
javascript
request.get('https://www.psohubapp.com/rest/psohubapi/v1/project?limit=50', { headers: { 'Authorization': `Bearer ${ACCESS_TOKEN}`, 'Content-Type': 'application/json' } }, (err, data) => { // Handle the API response });
How to Refresh Your Access Token
Access tokens expire after the period specified in expires_in. To obtain a new access token without requiring the user to re-authorize, exchange your refresh token using the endpoint below.
Endpoint
POST https://www.psohubapp.com/oauth/token
Request parameters
| Parameter | Description | Example |
|---|---|---|
| grant_type | Must be refresh_token. |
refresh_token |
| client_id | Your app's Client ID. | 7fff1e36-2d40-4ae1-bbb1-5266d59564fb |
| client_secret | Your app's Client Secret. | 7c3ce02c-0f0c-4c9f-9700-92440c9bdf2d |
| redirect_uri | The redirect URI used when the user authorized your app. | https://www.example.com/auth-callback |
| refresh_token | The refresh token received during the authorization code exchange. | b9443019-30fe-4df1-a67e-3d75cbd0f726 |
Example request
javascript
const formData = { grant_type: 'refresh_token', client_id: CLIENT_ID, client_secret: CLIENT_SECRET, redirect_uri: REDIRECT_URI, refresh_token: REFRESH_TOKEN }; request.post('https://www.psohubapp.com/oauth/token', { form: formData }, (err, data) => { // Handle the returned tokens });
Example response
json
{ "refresh_token": "6f18f21e-a743-4509-b7fd-1a5e632fffa1", "access_token": "CN2zlYnmLBICAQIYgZXFLyCWp1Yoy_9GMhkAgddk-zDc-H_rOad1X2s6Qv3fmG1spSY0Og0ACgJBAAADAIADAAABQhkAgddk-03q2qdkwdXbYWCoB9g3LA97OJ9I", "expires_in": 600 }
When the new access token expires, repeat the refresh steps to obtain another one.
📌 Note: If an error occurs at any point in the authentication flow, PSOhub returns an explicit error message identifying the problem.