Skip to content

Oauth2 Support#1172

Closed
kickster97 wants to merge 116 commits intomainfrom
temp-user
Closed

Oauth2 Support#1172
kickster97 wants to merge 116 commits intomainfrom
temp-user

Conversation

@kickster97
Copy link
Member

@kickster97 kickster97 commented Jun 25, 2025

WHAT is this pull request doing?

Add OAuth2/OpenID Connect authentication to LavinMQ. Clients can now authenticate using JWT tokens (RS256) as the password field. The authenticator validates tokens against the OAuth provider's JWKS endpoint, checks issuer/audience/expiration, and maps scopes to LavinMQ permissions. Supports token refresh via UpdateSecret frame without reconnecting. JWKS public keys are cached with configurable TTL.

Refactors the user system into an abstract User base class with LocalUser (password-based) and OAuthUser (token-based with expiration tracking) implementations. Authentication chain tries local auth first, then OAuth.

fixes #857

HOW can this pull request be tested?

specs to come once we are satisfied with the general logic and structure

@claude
Copy link

claude bot commented Aug 8, 2025

Claude finished @kickster97's task —— View job


OAuth2 Support PR Code Review

Reviewing this PR for bugs, security vulnerabilities, performance issues, missing error handling, and Crystal anti-patterns.

Todo List

  • Read repository guidelines (CLAUDE.md)
  • Review core OAuth authentication files
  • Examine JWT handling and verification logic
  • Check user management and security patterns
  • Review configuration and error handling
  • Post findings

Issues Found

🚨 Critical Security Vulnerability

  1. Timing Attack in Public Keys Iteration (src/lavinmq/auth/public_keys.cr:54-58):
    keys.each_value do |key|
      return JWT::RS256Parser.decode(token, key, verify: true)
    rescue JWT::VerificationError
    end
    This creates a timing side channel - successful verification returns immediately while failed verification continues iterating. Attackers could use timing analysis to determine key ordering and potentially extract key information.

🛡️ Security Issues
2. Insufficient Error Context for Security Events (src/lavinmq/auth/jwt_token_verifier.cr:101-103):

  • Issuer validation error doesn't log what the actual issuer was, making security incident investigation difficult
  • Should log expected vs actual issuer for security monitoring
  1. Resource Exhaustion Vulnerability (src/lavinmq/auth/oauth_user.cr:26):
    when timeout(token_lifetime)
    If token_lifetime is negative (expired token), this could cause very short timeouts, potentially creating a busy-loop that consumes CPU resources.

⚠️ Missing Error Handling
4. Uncaught LibCrypto Exceptions (src/lavinmq/auth/jwks_fetcher.cr:73-96):

  • Multiple LibCrypto calls that could fail but errors get converted to generic "Failed to create X" messages
  • Should have more specific error handling for different OpenSSL failure modes
  1. Network Timeout Missing Retry Logic (src/lavinmq/auth/jwks_fetcher.cr:128-139):
    • HTTP client has timeouts but no retry mechanism for transient network failures
    • Could cause authentication failures during temporary network issues

🐛 Potential Bugs
6. Race Condition in Token Update (src/lavinmq/auth/oauth_user.cr:47):

@token_updated.send nil

If multiple token updates happen rapidly, the channel send could block or messages could be lost, potentially leaving the expiration fiber in an inconsistent state.

  1. Integer Overflow in Cache TTL (src/lavinmq/auth/jwks_fetcher.cr:60):
    return match[1].to_i.seconds
    No bounds checking on the parsed integer - malicious JWKS response could specify extremely large max-age values.

📈 Performance Issues
8. Inefficient Scope Processing (src/lavinmq/auth/jwt_token_verifier.cr:183-194):

  • Creates multiple intermediate arrays during scope filtering
  • Could be optimized with lazy evaluation for large scope lists

🔧 Crystal Anti-patterns
9. Mixed Exception Types in Rescue (src/lavinmq/auth/oauth_authenticator.cr:31-33):

rescue ex : Exception

Catching generic Exception after specific JWT exceptions violates Crystal's exception handling patterns.

  1. Unsafe Type Casting (src/lavinmq/auth/jwt_token_verifier.cr:66-67):
    exp = payload["exp"]?.try(&.as_i64?)
    Should validate that the exp value is reasonable (not negative, not too far in future) before using it.

@kickster97 kickster97 changed the title WIP: Temporary user type Temporary User and Oauth Support Oct 8, 2025
@kickster97 kickster97 marked this pull request as ready for review October 8, 2025 16:51
@kickster97 kickster97 requested a review from a team as a code owner October 8, 2025 16:51
@kickster97 kickster97 force-pushed the temp-user branch 2 times, most recently from 94d5705 to 66eac18 Compare October 8, 2025 17:04
@kickster97 kickster97 changed the title Temporary User and Oauth Support Temporary-User and Oauth Support Oct 8, 2025
@carlhoerberg
Copy link
Member

For sure should implement our own JWT parser, it's not many lines of code: https://claude.ai/artifacts/82992d3e-5e0d-4e0e-8205-bb29f7a0dce1

@carlhoerberg
Copy link
Member

Is the the TempUsers class really necessary? Can't the original UserStore be used? The only difference between BasicUser and TempUser is the expiration? Can/should the expiration time be nilable and added to the normal User? Or should the old User be kept we just create a new TempUser that inherits from it?

@kickster97
Copy link
Member Author

kickster97 commented Oct 10, 2025

Is the the TempUsers class really necessary? Can't the original UserStore be used? The only difference between BasicUser and TempUser is the expiration? Can/should the expiration time be nilable and added to the normal User? Or should the old User be kept we just create a new TempUser that inherits from it?

Yes sounds good, Could override the methods that need password in UserStore for TempUsers and let TempUser inherit User. I still think it makes sense for temporary users to have its own class TempUser, due to expire and password etc..

@kickster97 kickster97 changed the title Temporary-User and Oauth Support TempUser and Oauth Support Oct 10, 2025
Copy link
Member

@spuun spuun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename User to BasicUser and introduce an abstract base class User. Rename TempUser to OAuthUser and let it inherit thew new abstract User.

Remove all TempUser handling code in UserStore

@antondalgren antondalgren removed their request for review October 28, 2025 14:40
@kickster97 kickster97 force-pushed the temp-user branch 2 times, most recently from 2e7a1f7 to ffed68a Compare November 4, 2025 12:17
@kickster97 kickster97 changed the title TempUser and Oauth Support Oauth2 Support Nov 11, 2025
@kickster97 kickster97 force-pushed the temp-user branch 3 times, most recently from fd08404 to 4a52ebf Compare November 12, 2025 15:26
Copy link
Member

@spuun spuun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job!
I've got some questions and suggestions.

kickster97 and others added 5 commits December 11, 2025 09:31
Co-authored-by: Carl Hörberg <carl@84codes.com>
Co-authored-by: Carl Hörberg <carl@84codes.com>
Co-authored-by: Carl Hörberg <carl@84codes.com>
Co-authored-by: Carl Hörberg <carl@84codes.com>
@kickster97 kickster97 marked this pull request as draft December 15, 2025 07:59
snichme and others added 5 commits December 15, 2025 13:03
### WHAT is this pull request doing?

Adds additional checks on the token, checking aud, kty and more fields 
Split OauthAuthenticator and TokenVerifier into different classes and
refactor signatures for easier testing
Add testing to the new JWTTokenVerifier 

Each commit can be cherry picked into target branch unless we want all
changes.
@kickster97 kickster97 marked this pull request as ready for review December 18, 2025 11:35
@kickster97
Copy link
Member Author

closing here to get a cleaner PR to wrok with in #1632 :)

@kickster97 kickster97 closed this Jan 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Oauth2 Support

5 participants