simple-oauth2
semver
>=4.0.0 <6.0.0postconditions9functions4last verified2026-04-17coverage score100%Postconditions — what we check
- getToken · network-errorerrorWhenNetwork error, connection timeout, or DNS resolution failure when contacting the OAuth2 serverThrows
Error with network error details (no response body)Required handlingCaller MUST wrap getToken() in try-catch to handle network failures. Network errors have no response body; check error.message for details. Implement retry with exponential backoff for transient network failures.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - getToken · invalid-credentialserrorWhenOAuth2 server returns 401 Unauthorized (invalid client_id, client_secret, or credentials)Throws
Error with response body containing OAuth2 error descriptionRequired handlingCaller MUST catch this error and handle configuration failures. DO NOT retry invalid credentials automatically — this indicates a configuration error. Error object includes response.status and OAuth2 error details in the message.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - getToken · server-errorerrorWhenOAuth2 server returns 4xx or 5xx status codeThrows
Error with HTTP status and response bodyRequired handlingCaller MUST catch and inspect the error. For 5xx errors, implement retry logic. For 4xx client errors, log and surface to operations — retrying without fixing the configuration will not resolve the issue.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - refresh · refresh-token-expired-or-invaliderrorWhenThe refresh token has expired, been revoked, or is invalidThrows
Error with OAuth2 error response (typically 400 Bad Request with invalid_grant)Required handlingCaller MUST catch refresh errors and handle re-authentication. When refresh fails with invalid_grant, the user MUST re-authenticate from scratch. DO NOT retry refresh token errors — the token is invalid and a new authorization flow is required.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - refresh · network-errorerrorWhenNetwork error when contacting the OAuth2 server during refreshThrows
Error with network error detailsRequired handlingCaller MUST wrap refresh() in try-catch and implement retry logic for network failures. Distinguish between network errors (retry safe) and OAuth2 errors (not retry safe).costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - revoke · revoke-network-errorerrorWhenNetwork error when contacting the OAuth2 server during revocationThrows
Error with network error detailsRequired handlingCaller MUST wrap revoke() in try-catch. Network errors during revocation do not guarantee whether the token was revoked or not. Log the error and treat the token as potentially still valid.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - revoke · revoke-server-errorerrorWhenOAuth2 server returns error during revocationThrows
Error with HTTP status and OAuth2 error responseRequired handlingCaller MUST catch errors from revoke() and handle revocation failures gracefully. If revocation fails, do not assume the token is invalid on the server side.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - revokeAll · revokeall-partial-failureerrorWhenrevokeAll() is called and the first internal revoke call (for the access_token) throws a network error, timeout, or HTTP error from the OAuth2 server. The second revoke call (for the refresh_token) is never executed because revokeAll() uses sequential await without try-catch between the two calls. As a result: - If access_token revoke fails: BOTH tokens may still be valid on the server - If access_token revoke succeeds but is not confirmed: the refresh_token is still valid and can be used to obtain new access tokens This creates a security-critical partial logout state — the user appears logged out on the client but their refresh token can still mint new access tokens.Throws
Boom.Boom error (isBoom: true) with one of: - output.statusCode 502 (Boom.badGateway): network error (ECONNREFUSED, DNS failure) - output.statusCode 504 (Boom.gatewayTimeout): request timeout - output.statusCode matching HTTP status: OAuth2 server returned 4xx/5xx All Boom errors have .isBoom === true, .message with details, and .output.statusCode with the effective HTTP status code.Required handlingNEVER use revokeAll() for security-sensitive logout flows without error handling. Wrap revokeAll() in try-catch AND consider calling revoke() twice separately to handle partial failures: // Preferred: handle each revocation independently try { await accessToken.revoke('access_token'); } catch (err) { console.error('access_token revocation failed:', err.message); // Decide: continue to refresh_token revoke? Or abort? } try { await accessToken.revoke('refresh_token'); } catch (err) { console.error('refresh_token revocation failed:', err.message); } If using revokeAll(), always catch and treat the session as potentially still valid — force re-authentication on the next request: try { await accessToken.revokeAll(); } catch (err) { // CRITICAL: refresh token may still be valid. // Mark the session as potentially compromised and // require re-authentication. logger.error('Token revocation incomplete:', err.message); throw new Error('Logout incomplete — please re-authenticate'); }costhighin prodsilent failureusers seesecurity breachvisibilitysilent - revokeAll · revokeall-network-errorerrorWhenNetwork error or timeout occurs when revokeAll() attempts the first HTTP request to the OAuth2 token revocation endpoint. The OAuth2 server is unreachable due to DNS failure, connection refused, socket timeout, or TLS error. Because revokeAll() does not retry or fallback, a transient network blip prevents any token from being revoked.Throws
Boom.Boom error (isBoom: true): - Boom.badGateway (502): 'Client request error: <ECONNREFUSED|ENOTFOUND|...>' - Boom.gatewayTimeout (504): 'Client request timeout' Check: err.isBoom === true && err.output.statusCode in [502, 504]Required handlingCaller MUST wrap revokeAll() in try-catch. For network errors during logout, log the failure and implement a retry mechanism or fallback strategy (e.g., invalidate the session server-side even if the OAuth2 server could not be notified). Do not silently ignore revocation failures. try { await accessToken.revokeAll(); } catch (err) { if (err.isBoom && [502, 504].includes(err.output?.statusCode)) { // Network failure — could not reach revocation endpoint logger.warn('Token revocation network failure, session may persist:', err.message); // Invalidate server-side session anyway for security } throw err; }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
Sources
Every postcondition cites at least one of these. Numbered to match the footnotes above.
- [1]github.com/lelylan/simple-oauth2https://github.com/lelylan/simple-oauth2/blob/master/API.md
- [2]oauth.com/oauth2-servers/making-authenticated-requestshttps://www.oauth.com/oauth2-servers/making-authenticated-requests/refreshing-an-access-token/
- [3]github.com/lelylan/simple-oauth2https://github.com/lelylan/simple-oauth2/blob/master/lib/access-token.js
- [4]github.com/hapijs/wreckhttps://github.com/hapijs/wreck/blob/master/lib/index.js
Need a different package?
Request a profile