Commit bfe0874
feat: add OAuth 2.0 (3LO) authentication support (#380)
* feat: add OAuth 2.0 (3LO) authentication support
Implements OAuth 2.0 three-legged authentication for Atlassian Cloud services as requested in issue #251.
Key features:
- OAuth2Service interface and implementation for handling OAuth flows
- Support for authorization URL generation, token exchange, and refresh
- Integration with existing client through functional options pattern
- Accessible resources API support for multi-site authentication
- Comprehensive tests and example implementation
The implementation maintains backward compatibility by:
- Not modifying the existing Authentication interface
- Using functional options (WithOAuth) for client configuration
- OAuth tokens work seamlessly with existing bearer token support
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: resolve golangci-lint unused function warning
Convert callbackHandler to ExampleCallbackHandler to fix unused function warning
* feat: add automatic OAuth token renewal support
- Add WithOAuthAutoRenew option for automatic token refresh
- Implement token caching with ReuseTokenSource (5-minute expiry buffer)
- Create OAuth2 transport wrapper for automatic authorization headers
- Thread-safe token renewal with proper mutex handling
- Update refresh tokens when new ones are provided
- Add comprehensive tests for token renewal functionality
- Add example demonstrating auto-renewal usage
- Update README with auto-renewal documentation
* refactor: improve OAuth API with better separation of concerns
- Separate OAuth configuration from token management
- WithOAuth(config) now only sets up OAuth service
- WithAutoRenewalToken(token) enables auto-renewal (requires OAuth)
- WithOAuthWithAutoRenewal(config, token) as convenience method
- Fix unexported field issue in Transport struct
- Convert example main functions to proper Example functions
- Add comprehensive example showing new API usage
- Update documentation to reflect cleaner API design
The new API provides better separation of concerns:
- OAuth service configuration is independent of token management
- Auto-renewal is an explicit opt-in feature
- Clearer error messages when dependencies aren't met
* docs: fix markdown formatting in OAuth sections
- Fix line length issues by breaking long lines
- Clean up code examples for better readability
- Improve code formatting and indentation
- Add proper spacing in multi-site example
- Use consistent variable naming (ctx instead of context.Background())
* feat: add HTTP server examples for OAuth 2.0 callback handling
Add two comprehensive examples showing OAuth integration with HTTP servers:
1. jira_oauth2_simple_server_example.go:
- Minimal HTTP server setup for OAuth callback
- Basic callback handling with CSRF protection
- Simple HTML interface for OAuth flow
- Demonstrates auto-renewal client creation
2. jira_oauth2_http_server_example.go:
- Full-featured OAuth server with HTML interface
- Complete callback handling with error pages
- Site discovery and resource listing
- Proper server lifecycle management
- CSRF protection with random state generation
- Comprehensive error handling and user feedback
Both examples demonstrate:
- Proper OAuth callback URL handling
- State parameter verification for security
- Token exchange and auto-renewal setup
- Integration with accessible resources API
- Clean separation between OAuth flow and API usage
Update README with links to new HTTP server examples.
* feat: extend OAuth 2.0 support to all API clients
- Add OAuth support to all 9 API clients (Jira v2, Agile, SM, Confluence v1/v2, Admin, Assets, Bitbucket)
- Implement consistent ClientOption pattern with WithOAuth(), WithAutoRenewalToken(), WithOAuthWithAutoRenewal()
- Maintain backward compatibility - existing code continues to work
- Add multi-service OAuth example demonstrating usage across services
- Update README with comprehensive OAuth documentation for all clients
- Enable bearer token authentication for Assets client
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: resolve build and lint issues in multi-service OAuth example
- Fix Confluence v2 API method calls: use Space.Bulk() instead of Space.Gets()
- Fix Admin Organization API calls: use correct cursor parameter and access org.Attributes.Name
- Rename main() function to ExampleMain() to avoid conflicts with other examples
- Ensure all API calls use correct method signatures and data structures
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: add external token storage support for OAuth2
Implement TokenStore and TokenCallback interfaces to enable external storage
of OAuth2 tokens (Redis, files, databases, etc.) and token refresh callbacks.
Key changes:
- Add TokenStore interface for persistent token storage
- Add TokenCallback interface for token refresh notifications
- Enhance ReuseTokenSource and RefreshTokenSource with storage support
- Add WithTokenStore and WithTokenCallback client options
- Maintain full backward compatibility
Examples added:
- Redis-based token storage implementation
- File-based token storage implementation
- In-memory storage demonstration
This allows distributed applications to share tokens across instances
and enables monitoring/auditing of token refresh events.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: simplify OAuth2 examples and fix build issues
- Add build tags to prevent multiple main functions
- Reduce OAuth2 examples from 7 to 5 focused examples
- Remove redundant examples (simple server, new flow)
- Rename examples for clarity and consistency
- Fix compilation issues with examples
- Add overview comment explaining example structure
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: implement token storage support for all API clients
Add external token storage support to all 9 API clients without code duplication:
- Create shared HTTPWrapper and helper functions in oauth2 package
- Add WithTokenStore and WithTokenCallback options to all clients
- Update WithAutoRenewalToken to use shared token source setup logic
- Maintain backward compatibility with existing OAuth implementation
This allows all clients to use external storage (Redis, files, databases)
for tokens in distributed applications while keeping the code DRY.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: run go mod tidy
Clean up module dependencies and fix line endings
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: make refresh token storage synchronous and handle errors properly
Critical fix for token storage reliability:
- Make SetRefreshToken synchronous since refresh tokens are irreplaceable
- Return errors from Token() if refresh token storage fails
- Keep SetToken async for performance (access tokens can be refreshed)
- Add comprehensive documentation explaining the design rationale
- Add tests to verify refresh token storage errors are propagated
This prevents silent failures where refresh tokens could be lost,
forcing users to re-authenticate. The async behavior for access tokens
is retained for performance since they can be regenerated.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 19d1551 commit bfe0874
26 files changed
Lines changed: 4496 additions & 300 deletions
File tree
- admin
- assets
- bitbucket
- confluence
- v2
- examples
- jira
- agile
- sm
- v2
- v3
- pkg/infra/oauth2
- service/common
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
18 | 19 | | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
19 | 117 | | |
20 | | - | |
21 | | - | |
| 118 | + | |
| 119 | + | |
22 | 120 | | |
23 | 121 | | |
24 | 122 | | |
| |||
56 | 154 | | |
57 | 155 | | |
58 | 156 | | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
59 | 164 | | |
60 | 165 | | |
61 | 166 | | |
| |||
67 | 172 | | |
68 | 173 | | |
69 | 174 | | |
| 175 | + | |
| 176 | + | |
70 | 177 | | |
71 | 178 | | |
72 | 179 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
18 | 19 | | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
19 | 117 | | |
20 | 118 | | |
21 | | - | |
| 119 | + | |
22 | 120 | | |
23 | 121 | | |
24 | 122 | | |
| |||
53 | 151 | | |
54 | 152 | | |
55 | 153 | | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
56 | 161 | | |
57 | 162 | | |
58 | 163 | | |
| |||
64 | 169 | | |
65 | 170 | | |
66 | 171 | | |
| 172 | + | |
| 173 | + | |
67 | 174 | | |
68 | 175 | | |
69 | 176 | | |
| |||
120 | 227 | | |
121 | 228 | | |
122 | 229 | | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
123 | 235 | | |
124 | 236 | | |
125 | 237 | | |
| |||
0 commit comments