Prerequisites
Before starting, you need:- Client ID: Your application identifier (e.g.,
my-app) - Client Secret: Secret key for authentication (provided by Penbox)
- Redirect URI: HTTPS URL where users will be sent after authorization
OAuth2 Flow Overview
The authentication process follows the standard OAuth2 Authorization Code flow:Step 1: Redirect to Authorization
Create a “Connect Penbox” button in your application that redirects users to:Parameters
| Parameter | Required | Description |
|---|---|---|
client_id | Yes | Your client ID provided by Penbox |
redirect_uri | Yes | HTTPS URL where users will be redirected after authorization |
state | No | Random string to prevent CSRF attacks (recommended) |
response_type | No | Grant type: code (default) or token |
scope | No | Requested scopes, default: offline_access |
Example Redirect
Step 2: User Authorization
After redirection, the user will:- Log in to Penbox (if not already logged in)
- Select a company (workspace) to authorize
- Approve your application’s access request
- Your application name
- Which company they’re authorizing
- What permissions you’re requesting
Step 3: Handle Redirect Callback
After authorization, the user is redirected back to yourredirect_uri with query parameters.
Success Response
| Parameter | Description |
|---|---|
code | Authorization code to exchange for tokens (valid for 10 minutes) |
state | The state you provided (verify this matches!) |
Error Response
| Parameter | Description |
|---|---|
error | Error code (e.g., access_denied, unauthorized_client) |
error_description | Human-readable error description |
state | The state you provided |
Step 4: Exchange Code for Tokens
Exchange the authorization code for an access token by making a POST request to/token.
Request
Parameters
| Parameter | Required | Description |
|---|---|---|
client_id | Yes | Your client ID |
client_secret | Yes | Your client secret |
grant_type | Yes | Must be authorization_code |
code | Yes | The authorization code received |
redirect_uri | Yes | Must match the redirect_uri from step 1 |
custom_data | No | Arbitrary data stored with the authorization |
Response
| Field | Description |
|---|---|
access_token | JWT token to use for API requests (valid for 24 hours) |
refresh_token | Token to get a new access_token when it expires |
id_token | JWT with user information (optional) |
token_type | Always Bearer |
expiresIn | Token lifetime in seconds (86400 = 24 hours) |
The
refresh_token is only provided if you requested the offline_access scope (which is the default).Step 5: Use Access Token
Include the access token in theAuthorization header for all API requests:
Example: Create a Request
Refreshing Access Tokens
Access tokens expire after 24 hours. Use the refresh token to get a new access token without requiring user re-authorization.Request
Parameters
| Parameter | Required | Description |
|---|---|---|
client_id | Yes | Your client ID |
client_secret | Yes | Your client secret |
grant_type | Yes | Must be refresh_token |
refresh_token | Yes | The refresh token received during authorization |
Response
Custom Data
Thecustom_data field in the token exchange allows you to store arbitrary data with the authorization. This is useful for linking Penbox accounts to your system’s users.
Example Use Cases
Store User ReferenceGrant Types
The Connect API supports two OAuth2 grant types:Authorization Code (Recommended)
Use for: Server-side applications where you can securely store the client_secret.Implicit Grant
Use for: Client-side applications (SPAs) where client_secret cannot be stored securely.Token Security
Storing Tokens
Access Tokens- Store securely server-side (encrypted database, secure session)
- Never expose in client-side code or URLs
- Rotate regularly (every 24 hours via refresh)
- Treat as highly sensitive credentials
- Encrypt at rest in your database
- Never send to client-side code
- Implement rotation on refresh
Revoking Access
Users can revoke your application’s access at any time through their Penbox account settings. When this happens:- All access tokens are immediately invalidated
- Refresh tokens no longer work
- API requests return
401 Unauthorized - You should prompt the user to re-authorize
Error Responses
Authorization Errors
| Error Code | Description | Action |
|---|---|---|
access_denied | User denied authorization | Inform user, allow retry |
unauthorized_client | Invalid client_id or redirect_uri | Check configuration |
invalid_request | Missing or invalid parameters | Fix request parameters |
server_error | Penbox internal error | Retry later |
Token Exchange Errors
| Error Code | Description | Action |
|---|---|---|
invalid_grant | Invalid or expired authorization code | Request new authorization |
invalid_client | Invalid client credentials | Check client_id and client_secret |
unauthorized_client | Client not authorized for this grant type | Contact Penbox support |
Best Practices
Use state parameter
Use state parameter
Always include a random
state parameter and verify it matches on the callback to prevent CSRF attacks.Implement token refresh
Implement token refresh
Proactively refresh access tokens before they expire (e.g., after 23 hours) to avoid API disruptions.
Handle errors gracefully
Handle errors gracefully
Implement proper error handling for authorization failures, token expiration, and revocation.
Store tokens securely
Store tokens securely
Never expose tokens in client-side code, URLs, or logs. Encrypt refresh tokens at rest.
Request minimal scopes
Request minimal scopes
Only request the scopes your application actually needs.
Monitor token usage
Monitor token usage
Track token usage and expiration to detect issues early.