Onshape OAuth 401 Error: Complete Authentication Fix Guide
The Quick Fix
Onshape OAuth 401 errors are almost always caused by improper URL encoding of client credentials, especially trailing = characters in client secrets.
Why Onshape OAuth Fails
The #1 Cause: URL Encoding Issues
// WRONG - This will cause 401
const clientSecret = "abc123==";
const body = `client_id=${clientId}&client_secret=${clientSecret}`;
// CORRECT - URL encode everything
const body = `client_id=${encodeURIComponent(clientId)}&client_secret=${encodeURIComponent(clientSecret)}`;
Real Developer Quote:
βThe body of the form needs to contain the client ID, client secret, authorization_codeβ¦ Each of the parameters in the POST body need to be URL encoded - this is especially important for the Client ID and secret since either or both may contain multiple trailing β=β characters.β
Complete OAuth Implementation
Step 1: Proper Token Request
async function getOnshapeToken(code) {
const params = new URLSearchParams();
params.append('grant_type', 'authorization_code');
params.append('client_id', CLIENT_ID);
params.append('client_secret', CLIENT_SECRET);
params.append('code', code);
params.append('redirect_uri', REDIRECT_URI);
const response = await fetch('https://oauth.onshape.com/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
},
body: params.toString() // URLSearchParams handles encoding
});
if (!response.ok) {
const error = await response.text();
console.error('OAuth failed:', response.status, error);
throw new Error(`OAuth 401: ${error}`);
}
return response.json();
}
Step 2: Handle Refresh Tokens
async function refreshOnshapeToken(refreshToken) {
const params = new URLSearchParams();
params.append('grant_type', 'refresh_token');
params.append('client_id', CLIENT_ID);
params.append('client_secret', CLIENT_SECRET);
params.append('refresh_token', refreshToken);
const response = await fetch('https://oauth.onshape.com/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: params.toString()
});
if (response.status === 401) {
// Refresh token expired - need full reauth
throw new Error('Refresh token expired - reauthenticate');
}
return response.json();
}
Common 401 Scenarios
Scenario 1: Webhook Response Codes
Problem: Returning wrong HTTP status
// WRONG - Causes webhook deregistration
res.status(201).send('Created');
// CORRECT - Onshape requires exactly 200
res.status(200).send('OK');
Scenario 2: Authorization Header Format
Problem: Incorrect Bearer token format
// WRONG
headers: {
'Authorization': accessToken
}
// CORRECT
headers: {
'Authorization': `Bearer ${accessToken}`
}
Scenario 3: Expired Tokens
Problem: Not handling token expiration
// Implement token refresh before expiry
if (Date.now() >= tokenExpiryTime - 60000) { // Refresh 1 min early
const newTokens = await refreshOnshapeToken(refreshToken);
accessToken = newTokens.access_token;
refreshToken = newTokens.refresh_token;
tokenExpiryTime = Date.now() + (newTokens.expires_in * 1000);
}
Python Implementation
import urllib.parse
import requests
import base64
def get_onshape_token(code, client_id, client_secret, redirect_uri):
"""Get Onshape OAuth token with proper encoding"""
# URL encode all parameters
data = {
'grant_type': 'authorization_code',
'client_id': client_id,
'client_secret': client_secret,
'code': code,
'redirect_uri': redirect_uri
}
# Use requests library encoding
response = requests.post(
'https://oauth.onshape.com/oauth/token',
data=data, # requests handles URL encoding
headers={
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
}
)
if response.status_code == 401:
print(f"401 Error: {response.text}")
# Common issues to check:
# 1. Client secret has trailing '=' not encoded
# 2. Redirect URI doesn't match exactly
# 3. Authorization code expired (very short TTL)
raise Exception(f"OAuth failed: {response.text}")
return response.json()
Debugging 401 Errors
Enable Detailed Logging
// Log exact request being sent
console.log('OAuth Request:', {
url: 'https://oauth.onshape.com/oauth/token',
body: params.toString(),
headers: headers
});
// Log raw response
const responseText = await response.text();
console.log('OAuth Response:', response.status, responseText);
Common Error Messages
| Error Message | Cause | Solution |
|---|---|---|
invalid_client |
Client ID/Secret wrong | Check encoding, trailing spaces |
invalid_grant |
Code expired or invalid | Codes expire quickly, use immediately |
invalid_request |
Malformed request | Check Content-Type header |
unauthorized_client |
App not authorized | Check Onshape app settings |
Local Testing Challenges
HTTPS Certificate Requirements
Onshape webhooks require valid HTTPS certificates:
// WRONG - Self-signed certificate
https.createServer({
key: fs.readFileSync('self-signed.key'),
cert: fs.readFileSync('self-signed.cert')
}, app);
// CORRECT - Use ngrok or similar
// Terminal: ngrok http 3000
// Use the ngrok HTTPS URL for webhooks
Comparison with Other Platforms
| Platform | OAuth Complexity | Common 401 Cause |
|---|---|---|
| Onshape | HIGH | URL encoding of secrets |
| Autodesk APS | HIGH | 2-legged vs 3-legged confusion |
| 3DEXPERIENCE | HIGH | Multi-platform sessions |
| Teamcenter | HIGH | SSO configuration |
Best Practices
1. Always Use URL Encoding Libraries
// Good - Let libraries handle encoding
const params = new URLSearchParams();
// Bad - Manual string concatenation
const body = `param=${value}`;
2. Implement Exponential Backoff
async function retryWithBackoff(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.message.includes('401') && i < maxRetries - 1) {
await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
} else {
throw error;
}
}
}
}
3. Store Tokens Securely
// Use environment variables
const CLIENT_SECRET = process.env.ONSHAPE_CLIENT_SECRET;
// Never commit credentials
// .gitignore should include .env
Why This Matters
Onshape OAuth issues waste countless developer hours:
- No clear documentation on encoding requirements
- Error messages donβt indicate encoding issues
- Community forums full of confused developers
- Trial and error debugging
Tools That Can Help
URL Encoding Testers
- Online URL encoder/decoder tools
- Postman for testing OAuth flows
- Browser developer tools network tab
Authentication Libraries
- Passport.js Onshape strategy
- OAuth2 client libraries with proper encoding
SEO Keywords Covered
- onshape oauth 401 error
- onshape authentication failed
- onshape invalid client
- onshape url encoding oauth
- onshape bearer token 401
- onshape webhook authentication
- onshape api 401 unauthorized
Part of our Cross-Platform CAD API Error Solutions series. Because every platform has authentication pain, but the solutions are knowable.