Module: Sinatra::JwtAuth::Helpers

Defined in:
lib/sinatra/jwt_auth.rb

Instance Method Summary collapse

Instance Method Details

#authenticate!Object

Halts with 401 JSON if the Bearer token is missing, malformed, or fails cryptographic / claims verification. On success, sets DEPRECATED: This helper uses halt, which throws past Opal’s async boundary in # await: true routes. Use authenticate_or_401 instead and handle the returned [status, body] tuple explicitly.



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
# File 'lib/sinatra/jwt_auth.rb', line 69

def authenticate!
  warn "DEPRECATION WARNING: authenticate! uses halt which is unsafe in async routes. Use authenticate_or_401 instead."
  token = extract_bearer_token
  halt_unauthorized!('missing bearer token') if token.nil?

  verify_key = settings.respond_to?(:jwt_verify_key) && settings.jwt_verify_key ? settings.jwt_verify_key : settings.jwt_secret
  algorithm  = settings.respond_to?(:jwt_algorithm) ? settings.jwt_algorithm : 'HS256'

  begin
    payload, header = JWT.decode(token, verify_key, true, algorithm: algorithm).__await__
  rescue JWT::ExpiredSignature
    halt_unauthorized!('token expired')
  rescue JWT::ImmatureSignature
    halt_unauthorized!('token not yet valid')
  rescue JWT::IncorrectAlgorithm
    halt_unauthorized!('algorithm mismatch')
  rescue JWT::VerificationError
    halt_unauthorized!('signature verification failed')
  rescue JWT::DecodeError => e
    halt_unauthorized!("invalid token: #{e.message}")
  end

  @jwt_payload = payload
  @jwt_header  = header
  payload
end

#authenticate_or_401Object

Safe async-friendly authentication helper. Returns [nil, payload] on success, or [401, json_body] on failure. Does NOT use halt — the caller is responsible for checking the status and returning early with status N; next(body).



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/sinatra/jwt_auth.rb', line 100

def authenticate_or_401
  token = extract_bearer_token
  return [401, { 'error' => 'unauthorized', 'reason' => 'missing bearer token' }.to_json] if token.nil?

  verify_key = settings.respond_to?(:jwt_verify_key) && settings.jwt_verify_key ? settings.jwt_verify_key : settings.jwt_secret
  algorithm  = settings.respond_to?(:jwt_algorithm) ? settings.jwt_algorithm : 'HS256'

  begin
    payload, header = JWT.decode(token, verify_key, true, algorithm: algorithm).__await__
  rescue JWT::ExpiredSignature
    return [401, { 'error' => 'unauthorized', 'reason' => 'token expired' }.to_json]
  rescue JWT::ImmatureSignature
    return [401, { 'error' => 'unauthorized', 'reason' => 'token not yet valid' }.to_json]
  rescue JWT::IncorrectAlgorithm
    return [401, { 'error' => 'unauthorized', 'reason' => 'algorithm mismatch' }.to_json]
  rescue JWT::VerificationError
    return [401, { 'error' => 'unauthorized', 'reason' => 'signature verification failed' }.to_json]
  rescue JWT::DecodeError => e
    return [401, { 'error' => 'unauthorized', 'reason' => "invalid token: #{e.message}" }.to_json]
  end

  @jwt_payload = payload
  @jwt_header  = header
  [nil, payload]
end

#current_userObject

Returns the decoded payload Hash, or nil if the request has not been authenticated (or authentication failed).



50
51
52
# File 'lib/sinatra/jwt_auth.rb', line 50

def current_user
  @jwt_payload
end

#issue_token(payload, expires_in: 3600, extra_headers: {}) ⇒ Object

Mints a new token using the configured signing key + algorithm. ‘expires_in` adds an `exp` claim in seconds from now; pass nil to leave it off. `extra_headers` is merged into the JWT header alongside the alg.



130
131
132
133
134
135
136
137
138
139
# File 'lib/sinatra/jwt_auth.rb', line 130

def issue_token(payload, expires_in: 3600, extra_headers: {})
  sign_key  = settings.respond_to?(:jwt_sign_key) && settings.jwt_sign_key ? settings.jwt_sign_key : settings.jwt_secret
  algorithm = settings.respond_to?(:jwt_algorithm) ? settings.jwt_algorithm : 'HS256'
  claims    = payload.dup
  if expires_in
    claims['exp'] = Time.now.to_i + expires_in.to_i
    claims['iat'] = Time.now.to_i
  end
  JWT.encode(claims, sign_key, algorithm, extra_headers).__await__
end

#jwt_headerObject



58
59
60
# File 'lib/sinatra/jwt_auth.rb', line 58

def jwt_header
  @jwt_header
end

#jwt_payloadObject



54
55
56
# File 'lib/sinatra/jwt_auth.rb', line 54

def jwt_payload
  @jwt_payload
end