Class: Ably::Realtime::Auth

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Modules::AsyncWrapper
Defined in:
lib/ably/realtime/auth.rb

Overview

Auth is responsible for authentication with Ably using basic or token authentication This Realtime::Auth class wraps the Synchronous Ably::Auth class in an EventMachine friendly way using Deferrables for all IO. See Ably::Auth for more information

Find out more about Ably authentication at: www.ably.com/docs/general/authentication/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client) ⇒ Auth

Returns a new instance of Auth.



49
50
51
52
# File 'lib/ably/realtime/auth.rb', line 49

def initialize(client)
  @client = client
  @auth_sync = client.rest_client.auth
end

Instance Attribute Details

#authentication_security_requirements_met?Boolean (readonly)

Returns false when attempting to send an API Key over a non-secure connection Token auth must be used for non-secure connections

Returns:

  • (Boolean)


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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ably/realtime/auth.rb', line 35

class Auth
  extend Forwardable
  include Ably::Modules::AsyncWrapper

  def_delegators :auth_sync, :client_id
  def_delegators :auth_sync, :token_client_id_allowed?, :configure_client_id, :client_id_validated?
  def_delegators :auth_sync, :can_assume_client_id?, :has_client_id?
  def_delegators :auth_sync, :current_token_details, :token
  def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
  def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
  def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
  def_delegators :client, :logger
  def_delegators :client, :connection

  def initialize(client)
    @client = client
    @auth_sync = client.rest_client.auth
  end

  # For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary.
  # If a connection is already established, the connection will be upgraded with a new token
  #
  # In the event that a new token request is made, the provided options are used
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # will issue a simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.authorize do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def authorize(token_params = nil, auth_options = nil, &success_callback)
    Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
      # Wrap the sync authorize method and wait for the result from the deferrable
      async_wrap do
        authorize_sync(token_params, auth_options)
      end.tap do |auth_operation|
        # Authorize operation succeeded and we have a new token, now let's perform inline authentication
        auth_operation.callback do |token|
          case connection.state.to_sym
          when :initialized, :disconnected, :suspended, :closed, :closing, :failed
            connection.connect
          when :connected
            perform_inline_auth token
          when :connecting
            # Fail all current connection attempts and try again with the new token, see #RTC8b
            connection.manager.release_and_establish_new_transport
          else
            logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
            authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
            next
          end

          # Indicate success or failure based on response from realtime, see #RTC8b1
          auth_deferrable_resolved = false

          connection.unsafe_once(:connected, :update) do
            auth_deferrable_resolved = true
            authorize_method_deferrable.succeed token
          end
          connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
            auth_deferrable_resolved = true
            authorize_method_deferrable.fail state_change.reason
          end
        end

        # Authorize failed, likely due to auth_url or auth_callback failing
        auth_operation.errback do |error|
          client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
          authorize_method_deferrable.fail error
        end
      end

      # Call the block provided to this method upon success of this deferrable
      authorize_method_deferrable.callback do |token|
        yield token if block_given?
      end
    end
  end

  # @deprecated Use {#authorize} instead
  def authorise(*args, &block)
    logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
    authorize(*args, &block)
  end

  # Synchronous version of {#authorize}. See {Ably::Auth#authorize} for method definition
  # Please note that authorize_sync will however not upgrade the current connection's token as this requires
  # an synchronous operation to send the new authentication details to Ably over a realtime connection
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def authorize_sync(token_params = nil, auth_options = nil)
    @authorization_in_flight = true
    auth_sync.authorize(token_params, auth_options)
  ensure
    @authorization_in_flight = false
  end

  # @api private
  def authorization_in_flight?
    @authorization_in_flight
  end

  # @deprecated Use {#authorize_sync} instead
  def authorise_sync(*args)
    logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
    authorize_sync(*args)
  end

  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
  #
  # @param (see Ably::Auth#request_token)
  # @option (see Ably::Auth#request_token)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.request_token do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def request_token(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      request_token_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def request_token_sync(token_params = {}, auth_options = {})
    auth_sync.request_token(token_params, auth_options)
  end

  # Creates and signs a token request that can then subsequently be used by any client to request a token
  #
  # @param (see Ably::Auth#create_token_request)
  # @option (see Ably::Auth#create_token_request)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Models::TokenRequest]
  #
  # @example
  #   client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
  #     token_request #=> Ably::Models::TokenRequest
  #   end
  def create_token_request(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      create_token_request_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenRequest]
  #
  def create_token_request_sync(token_params = {}, auth_options = {})
    auth_sync.create_token_request(token_params, auth_options)
  end

  # Auth header string used in HTTP requests to Ably
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header(&success_callback)
    async_wrap(success_callback) do
      auth_header_sync
    end
  end

  # Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
  # @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header_sync
    auth_sync.auth_header
  end

  def client_id_for_request_sync
    auth_sync.client_id_for_request
  end

  # Auth params used in URI endpoint for Realtime connections
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Hash] Auth params for a new Realtime connection
  #
  def auth_params(&success_callback)
    fail_callback = lambda do |error, deferrable|
      logger.error { "Failed to authenticate: #{error}" }
      if error.kind_of?(Ably::Exceptions::BaseAblyException)
        # Use base exception if it exists carrying forward the status codes
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
      else
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
      end
    end
    async_wrap(success_callback, fail_callback) do
      auth_params_sync
    end
  end

  # Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
  # @return [Hash] Auth params for a new Realtime connection
  #
  def auth_params_sync
    auth_sync.auth_params
  end

  private
  # The synchronous Auth class instanced by the Rest client
  # @return [Ably::Auth]
  def auth_sync
    @auth_sync
  end

  def client
    @client
  end

  # Sends an AUTH ProtocolMessage on the existing connection triggering
  # an inline AUTH process, see #RTC8a
  def perform_inline_auth(token)
    logger.debug { "Performing inline AUTH with Ably using token #{token}" }
    connection.send_protocol_message(
      action: Ably::Models::ProtocolMessage::ACTION.Auth.to_i,
      auth: { access_token: token.token }
    )
  end
end

#client_idObject (readonly)



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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ably/realtime/auth.rb', line 35

class Auth
  extend Forwardable
  include Ably::Modules::AsyncWrapper

  def_delegators :auth_sync, :client_id
  def_delegators :auth_sync, :token_client_id_allowed?, :configure_client_id, :client_id_validated?
  def_delegators :auth_sync, :can_assume_client_id?, :has_client_id?
  def_delegators :auth_sync, :current_token_details, :token
  def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
  def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
  def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
  def_delegators :client, :logger
  def_delegators :client, :connection

  def initialize(client)
    @client = client
    @auth_sync = client.rest_client.auth
  end

  # For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary.
  # If a connection is already established, the connection will be upgraded with a new token
  #
  # In the event that a new token request is made, the provided options are used
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # will issue a simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.authorize do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def authorize(token_params = nil, auth_options = nil, &success_callback)
    Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
      # Wrap the sync authorize method and wait for the result from the deferrable
      async_wrap do
        authorize_sync(token_params, auth_options)
      end.tap do |auth_operation|
        # Authorize operation succeeded and we have a new token, now let's perform inline authentication
        auth_operation.callback do |token|
          case connection.state.to_sym
          when :initialized, :disconnected, :suspended, :closed, :closing, :failed
            connection.connect
          when :connected
            perform_inline_auth token
          when :connecting
            # Fail all current connection attempts and try again with the new token, see #RTC8b
            connection.manager.release_and_establish_new_transport
          else
            logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
            authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
            next
          end

          # Indicate success or failure based on response from realtime, see #RTC8b1
          auth_deferrable_resolved = false

          connection.unsafe_once(:connected, :update) do
            auth_deferrable_resolved = true
            authorize_method_deferrable.succeed token
          end
          connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
            auth_deferrable_resolved = true
            authorize_method_deferrable.fail state_change.reason
          end
        end

        # Authorize failed, likely due to auth_url or auth_callback failing
        auth_operation.errback do |error|
          client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
          authorize_method_deferrable.fail error
        end
      end

      # Call the block provided to this method upon success of this deferrable
      authorize_method_deferrable.callback do |token|
        yield token if block_given?
      end
    end
  end

  # @deprecated Use {#authorize} instead
  def authorise(*args, &block)
    logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
    authorize(*args, &block)
  end

  # Synchronous version of {#authorize}. See {Ably::Auth#authorize} for method definition
  # Please note that authorize_sync will however not upgrade the current connection's token as this requires
  # an synchronous operation to send the new authentication details to Ably over a realtime connection
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def authorize_sync(token_params = nil, auth_options = nil)
    @authorization_in_flight = true
    auth_sync.authorize(token_params, auth_options)
  ensure
    @authorization_in_flight = false
  end

  # @api private
  def authorization_in_flight?
    @authorization_in_flight
  end

  # @deprecated Use {#authorize_sync} instead
  def authorise_sync(*args)
    logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
    authorize_sync(*args)
  end

  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
  #
  # @param (see Ably::Auth#request_token)
  # @option (see Ably::Auth#request_token)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.request_token do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def request_token(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      request_token_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def request_token_sync(token_params = {}, auth_options = {})
    auth_sync.request_token(token_params, auth_options)
  end

  # Creates and signs a token request that can then subsequently be used by any client to request a token
  #
  # @param (see Ably::Auth#create_token_request)
  # @option (see Ably::Auth#create_token_request)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Models::TokenRequest]
  #
  # @example
  #   client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
  #     token_request #=> Ably::Models::TokenRequest
  #   end
  def create_token_request(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      create_token_request_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenRequest]
  #
  def create_token_request_sync(token_params = {}, auth_options = {})
    auth_sync.create_token_request(token_params, auth_options)
  end

  # Auth header string used in HTTP requests to Ably
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header(&success_callback)
    async_wrap(success_callback) do
      auth_header_sync
    end
  end

  # Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
  # @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header_sync
    auth_sync.auth_header
  end

  def client_id_for_request_sync
    auth_sync.client_id_for_request
  end

  # Auth params used in URI endpoint for Realtime connections
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Hash] Auth params for a new Realtime connection
  #
  def auth_params(&success_callback)
    fail_callback = lambda do |error, deferrable|
      logger.error { "Failed to authenticate: #{error}" }
      if error.kind_of?(Ably::Exceptions::BaseAblyException)
        # Use base exception if it exists carrying forward the status codes
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
      else
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
      end
    end
    async_wrap(success_callback, fail_callback) do
      auth_params_sync
    end
  end

  # Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
  # @return [Hash] Auth params for a new Realtime connection
  #
  def auth_params_sync
    auth_sync.auth_params
  end

  private
  # The synchronous Auth class instanced by the Rest client
  # @return [Ably::Auth]
  def auth_sync
    @auth_sync
  end

  def client
    @client
  end

  # Sends an AUTH ProtocolMessage on the existing connection triggering
  # an inline AUTH process, see #RTC8a
  def perform_inline_auth(token)
    logger.debug { "Performing inline AUTH with Ably using token #{token}" }
    connection.send_protocol_message(
      action: Ably::Models::ProtocolMessage::ACTION.Auth.to_i,
      auth: { access_token: token.token }
    )
  end
end

#current_token_detailsObject (readonly)

Returns the value of attribute current_token_details.



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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ably/realtime/auth.rb', line 35

class Auth
  extend Forwardable
  include Ably::Modules::AsyncWrapper

  def_delegators :auth_sync, :client_id
  def_delegators :auth_sync, :token_client_id_allowed?, :configure_client_id, :client_id_validated?
  def_delegators :auth_sync, :can_assume_client_id?, :has_client_id?
  def_delegators :auth_sync, :current_token_details, :token
  def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
  def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
  def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
  def_delegators :client, :logger
  def_delegators :client, :connection

  def initialize(client)
    @client = client
    @auth_sync = client.rest_client.auth
  end

  # For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary.
  # If a connection is already established, the connection will be upgraded with a new token
  #
  # In the event that a new token request is made, the provided options are used
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # will issue a simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.authorize do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def authorize(token_params = nil, auth_options = nil, &success_callback)
    Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
      # Wrap the sync authorize method and wait for the result from the deferrable
      async_wrap do
        authorize_sync(token_params, auth_options)
      end.tap do |auth_operation|
        # Authorize operation succeeded and we have a new token, now let's perform inline authentication
        auth_operation.callback do |token|
          case connection.state.to_sym
          when :initialized, :disconnected, :suspended, :closed, :closing, :failed
            connection.connect
          when :connected
            perform_inline_auth token
          when :connecting
            # Fail all current connection attempts and try again with the new token, see #RTC8b
            connection.manager.release_and_establish_new_transport
          else
            logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
            authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
            next
          end

          # Indicate success or failure based on response from realtime, see #RTC8b1
          auth_deferrable_resolved = false

          connection.unsafe_once(:connected, :update) do
            auth_deferrable_resolved = true
            authorize_method_deferrable.succeed token
          end
          connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
            auth_deferrable_resolved = true
            authorize_method_deferrable.fail state_change.reason
          end
        end

        # Authorize failed, likely due to auth_url or auth_callback failing
        auth_operation.errback do |error|
          client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
          authorize_method_deferrable.fail error
        end
      end

      # Call the block provided to this method upon success of this deferrable
      authorize_method_deferrable.callback do |token|
        yield token if block_given?
      end
    end
  end

  # @deprecated Use {#authorize} instead
  def authorise(*args, &block)
    logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
    authorize(*args, &block)
  end

  # Synchronous version of {#authorize}. See {Ably::Auth#authorize} for method definition
  # Please note that authorize_sync will however not upgrade the current connection's token as this requires
  # an synchronous operation to send the new authentication details to Ably over a realtime connection
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def authorize_sync(token_params = nil, auth_options = nil)
    @authorization_in_flight = true
    auth_sync.authorize(token_params, auth_options)
  ensure
    @authorization_in_flight = false
  end

  # @api private
  def authorization_in_flight?
    @authorization_in_flight
  end

  # @deprecated Use {#authorize_sync} instead
  def authorise_sync(*args)
    logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
    authorize_sync(*args)
  end

  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
  #
  # @param (see Ably::Auth#request_token)
  # @option (see Ably::Auth#request_token)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.request_token do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def request_token(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      request_token_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def request_token_sync(token_params = {}, auth_options = {})
    auth_sync.request_token(token_params, auth_options)
  end

  # Creates and signs a token request that can then subsequently be used by any client to request a token
  #
  # @param (see Ably::Auth#create_token_request)
  # @option (see Ably::Auth#create_token_request)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Models::TokenRequest]
  #
  # @example
  #   client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
  #     token_request #=> Ably::Models::TokenRequest
  #   end
  def create_token_request(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      create_token_request_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenRequest]
  #
  def create_token_request_sync(token_params = {}, auth_options = {})
    auth_sync.create_token_request(token_params, auth_options)
  end

  # Auth header string used in HTTP requests to Ably
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header(&success_callback)
    async_wrap(success_callback) do
      auth_header_sync
    end
  end

  # Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
  # @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header_sync
    auth_sync.auth_header
  end

  def client_id_for_request_sync
    auth_sync.client_id_for_request
  end

  # Auth params used in URI endpoint for Realtime connections
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Hash] Auth params for a new Realtime connection
  #
  def auth_params(&success_callback)
    fail_callback = lambda do |error, deferrable|
      logger.error { "Failed to authenticate: #{error}" }
      if error.kind_of?(Ably::Exceptions::BaseAblyException)
        # Use base exception if it exists carrying forward the status codes
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
      else
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
      end
    end
    async_wrap(success_callback, fail_callback) do
      auth_params_sync
    end
  end

  # Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
  # @return [Hash] Auth params for a new Realtime connection
  #
  def auth_params_sync
    auth_sync.auth_params
  end

  private
  # The synchronous Auth class instanced by the Rest client
  # @return [Ably::Auth]
  def auth_sync
    @auth_sync
  end

  def client
    @client
  end

  # Sends an AUTH ProtocolMessage on the existing connection triggering
  # an inline AUTH process, see #RTC8a
  def perform_inline_auth(token)
    logger.debug { "Performing inline AUTH with Ably using token #{token}" }
    connection.send_protocol_message(
      action: Ably::Models::ProtocolMessage::ACTION.Auth.to_i,
      auth: { access_token: token.token }
    )
  end
end

#keyObject (readonly)



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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ably/realtime/auth.rb', line 35

class Auth
  extend Forwardable
  include Ably::Modules::AsyncWrapper

  def_delegators :auth_sync, :client_id
  def_delegators :auth_sync, :token_client_id_allowed?, :configure_client_id, :client_id_validated?
  def_delegators :auth_sync, :can_assume_client_id?, :has_client_id?
  def_delegators :auth_sync, :current_token_details, :token
  def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
  def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
  def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
  def_delegators :client, :logger
  def_delegators :client, :connection

  def initialize(client)
    @client = client
    @auth_sync = client.rest_client.auth
  end

  # For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary.
  # If a connection is already established, the connection will be upgraded with a new token
  #
  # In the event that a new token request is made, the provided options are used
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # will issue a simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.authorize do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def authorize(token_params = nil, auth_options = nil, &success_callback)
    Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
      # Wrap the sync authorize method and wait for the result from the deferrable
      async_wrap do
        authorize_sync(token_params, auth_options)
      end.tap do |auth_operation|
        # Authorize operation succeeded and we have a new token, now let's perform inline authentication
        auth_operation.callback do |token|
          case connection.state.to_sym
          when :initialized, :disconnected, :suspended, :closed, :closing, :failed
            connection.connect
          when :connected
            perform_inline_auth token
          when :connecting
            # Fail all current connection attempts and try again with the new token, see #RTC8b
            connection.manager.release_and_establish_new_transport
          else
            logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
            authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
            next
          end

          # Indicate success or failure based on response from realtime, see #RTC8b1
          auth_deferrable_resolved = false

          connection.unsafe_once(:connected, :update) do
            auth_deferrable_resolved = true
            authorize_method_deferrable.succeed token
          end
          connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
            auth_deferrable_resolved = true
            authorize_method_deferrable.fail state_change.reason
          end
        end

        # Authorize failed, likely due to auth_url or auth_callback failing
        auth_operation.errback do |error|
          client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
          authorize_method_deferrable.fail error
        end
      end

      # Call the block provided to this method upon success of this deferrable
      authorize_method_deferrable.callback do |token|
        yield token if block_given?
      end
    end
  end

  # @deprecated Use {#authorize} instead
  def authorise(*args, &block)
    logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
    authorize(*args, &block)
  end

  # Synchronous version of {#authorize}. See {Ably::Auth#authorize} for method definition
  # Please note that authorize_sync will however not upgrade the current connection's token as this requires
  # an synchronous operation to send the new authentication details to Ably over a realtime connection
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def authorize_sync(token_params = nil, auth_options = nil)
    @authorization_in_flight = true
    auth_sync.authorize(token_params, auth_options)
  ensure
    @authorization_in_flight = false
  end

  # @api private
  def authorization_in_flight?
    @authorization_in_flight
  end

  # @deprecated Use {#authorize_sync} instead
  def authorise_sync(*args)
    logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
    authorize_sync(*args)
  end

  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
  #
  # @param (see Ably::Auth#request_token)
  # @option (see Ably::Auth#request_token)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.request_token do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def request_token(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      request_token_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def request_token_sync(token_params = {}, auth_options = {})
    auth_sync.request_token(token_params, auth_options)
  end

  # Creates and signs a token request that can then subsequently be used by any client to request a token
  #
  # @param (see Ably::Auth#create_token_request)
  # @option (see Ably::Auth#create_token_request)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Models::TokenRequest]
  #
  # @example
  #   client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
  #     token_request #=> Ably::Models::TokenRequest
  #   end
  def create_token_request(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      create_token_request_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenRequest]
  #
  def create_token_request_sync(token_params = {}, auth_options = {})
    auth_sync.create_token_request(token_params, auth_options)
  end

  # Auth header string used in HTTP requests to Ably
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header(&success_callback)
    async_wrap(success_callback) do
      auth_header_sync
    end
  end

  # Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
  # @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header_sync
    auth_sync.auth_header
  end

  def client_id_for_request_sync
    auth_sync.client_id_for_request
  end

  # Auth params used in URI endpoint for Realtime connections
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Hash] Auth params for a new Realtime connection
  #
  def auth_params(&success_callback)
    fail_callback = lambda do |error, deferrable|
      logger.error { "Failed to authenticate: #{error}" }
      if error.kind_of?(Ably::Exceptions::BaseAblyException)
        # Use base exception if it exists carrying forward the status codes
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
      else
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
      end
    end
    async_wrap(success_callback, fail_callback) do
      auth_params_sync
    end
  end

  # Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
  # @return [Hash] Auth params for a new Realtime connection
  #
  def auth_params_sync
    auth_sync.auth_params
  end

  private
  # The synchronous Auth class instanced by the Rest client
  # @return [Ably::Auth]
  def auth_sync
    @auth_sync
  end

  def client
    @client
  end

  # Sends an AUTH ProtocolMessage on the existing connection triggering
  # an inline AUTH process, see #RTC8a
  def perform_inline_auth(token)
    logger.debug { "Performing inline AUTH with Ably using token #{token}" }
    connection.send_protocol_message(
      action: Ably::Models::ProtocolMessage::ACTION.Auth.to_i,
      auth: { access_token: token.token }
    )
  end
end

#key_nameObject (readonly)



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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ably/realtime/auth.rb', line 35

class Auth
  extend Forwardable
  include Ably::Modules::AsyncWrapper

  def_delegators :auth_sync, :client_id
  def_delegators :auth_sync, :token_client_id_allowed?, :configure_client_id, :client_id_validated?
  def_delegators :auth_sync, :can_assume_client_id?, :has_client_id?
  def_delegators :auth_sync, :current_token_details, :token
  def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
  def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
  def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
  def_delegators :client, :logger
  def_delegators :client, :connection

  def initialize(client)
    @client = client
    @auth_sync = client.rest_client.auth
  end

  # For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary.
  # If a connection is already established, the connection will be upgraded with a new token
  #
  # In the event that a new token request is made, the provided options are used
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # will issue a simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.authorize do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def authorize(token_params = nil, auth_options = nil, &success_callback)
    Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
      # Wrap the sync authorize method and wait for the result from the deferrable
      async_wrap do
        authorize_sync(token_params, auth_options)
      end.tap do |auth_operation|
        # Authorize operation succeeded and we have a new token, now let's perform inline authentication
        auth_operation.callback do |token|
          case connection.state.to_sym
          when :initialized, :disconnected, :suspended, :closed, :closing, :failed
            connection.connect
          when :connected
            perform_inline_auth token
          when :connecting
            # Fail all current connection attempts and try again with the new token, see #RTC8b
            connection.manager.release_and_establish_new_transport
          else
            logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
            authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
            next
          end

          # Indicate success or failure based on response from realtime, see #RTC8b1
          auth_deferrable_resolved = false

          connection.unsafe_once(:connected, :update) do
            auth_deferrable_resolved = true
            authorize_method_deferrable.succeed token
          end
          connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
            auth_deferrable_resolved = true
            authorize_method_deferrable.fail state_change.reason
          end
        end

        # Authorize failed, likely due to auth_url or auth_callback failing
        auth_operation.errback do |error|
          client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
          authorize_method_deferrable.fail error
        end
      end

      # Call the block provided to this method upon success of this deferrable
      authorize_method_deferrable.callback do |token|
        yield token if block_given?
      end
    end
  end

  # @deprecated Use {#authorize} instead
  def authorise(*args, &block)
    logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
    authorize(*args, &block)
  end

  # Synchronous version of {#authorize}. See {Ably::Auth#authorize} for method definition
  # Please note that authorize_sync will however not upgrade the current connection's token as this requires
  # an synchronous operation to send the new authentication details to Ably over a realtime connection
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def authorize_sync(token_params = nil, auth_options = nil)
    @authorization_in_flight = true
    auth_sync.authorize(token_params, auth_options)
  ensure
    @authorization_in_flight = false
  end

  # @api private
  def authorization_in_flight?
    @authorization_in_flight
  end

  # @deprecated Use {#authorize_sync} instead
  def authorise_sync(*args)
    logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
    authorize_sync(*args)
  end

  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
  #
  # @param (see Ably::Auth#request_token)
  # @option (see Ably::Auth#request_token)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.request_token do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def request_token(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      request_token_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def request_token_sync(token_params = {}, auth_options = {})
    auth_sync.request_token(token_params, auth_options)
  end

  # Creates and signs a token request that can then subsequently be used by any client to request a token
  #
  # @param (see Ably::Auth#create_token_request)
  # @option (see Ably::Auth#create_token_request)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Models::TokenRequest]
  #
  # @example
  #   client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
  #     token_request #=> Ably::Models::TokenRequest
  #   end
  def create_token_request(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      create_token_request_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenRequest]
  #
  def create_token_request_sync(token_params = {}, auth_options = {})
    auth_sync.create_token_request(token_params, auth_options)
  end

  # Auth header string used in HTTP requests to Ably
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header(&success_callback)
    async_wrap(success_callback) do
      auth_header_sync
    end
  end

  # Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
  # @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header_sync
    auth_sync.auth_header
  end

  def client_id_for_request_sync
    auth_sync.client_id_for_request
  end

  # Auth params used in URI endpoint for Realtime connections
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Hash] Auth params for a new Realtime connection
  #
  def auth_params(&success_callback)
    fail_callback = lambda do |error, deferrable|
      logger.error { "Failed to authenticate: #{error}" }
      if error.kind_of?(Ably::Exceptions::BaseAblyException)
        # Use base exception if it exists carrying forward the status codes
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
      else
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
      end
    end
    async_wrap(success_callback, fail_callback) do
      auth_params_sync
    end
  end

  # Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
  # @return [Hash] Auth params for a new Realtime connection
  #
  def auth_params_sync
    auth_sync.auth_params
  end

  private
  # The synchronous Auth class instanced by the Rest client
  # @return [Ably::Auth]
  def auth_sync
    @auth_sync
  end

  def client
    @client
  end

  # Sends an AUTH ProtocolMessage on the existing connection triggering
  # an inline AUTH process, see #RTC8a
  def perform_inline_auth(token)
    logger.debug { "Performing inline AUTH with Ably using token #{token}" }
    connection.send_protocol_message(
      action: Ably::Models::ProtocolMessage::ACTION.Auth.to_i,
      auth: { access_token: token.token }
    )
  end
end

#key_secretObject (readonly)



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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ably/realtime/auth.rb', line 35

class Auth
  extend Forwardable
  include Ably::Modules::AsyncWrapper

  def_delegators :auth_sync, :client_id
  def_delegators :auth_sync, :token_client_id_allowed?, :configure_client_id, :client_id_validated?
  def_delegators :auth_sync, :can_assume_client_id?, :has_client_id?
  def_delegators :auth_sync, :current_token_details, :token
  def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
  def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
  def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
  def_delegators :client, :logger
  def_delegators :client, :connection

  def initialize(client)
    @client = client
    @auth_sync = client.rest_client.auth
  end

  # For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary.
  # If a connection is already established, the connection will be upgraded with a new token
  #
  # In the event that a new token request is made, the provided options are used
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # will issue a simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.authorize do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def authorize(token_params = nil, auth_options = nil, &success_callback)
    Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
      # Wrap the sync authorize method and wait for the result from the deferrable
      async_wrap do
        authorize_sync(token_params, auth_options)
      end.tap do |auth_operation|
        # Authorize operation succeeded and we have a new token, now let's perform inline authentication
        auth_operation.callback do |token|
          case connection.state.to_sym
          when :initialized, :disconnected, :suspended, :closed, :closing, :failed
            connection.connect
          when :connected
            perform_inline_auth token
          when :connecting
            # Fail all current connection attempts and try again with the new token, see #RTC8b
            connection.manager.release_and_establish_new_transport
          else
            logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
            authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
            next
          end

          # Indicate success or failure based on response from realtime, see #RTC8b1
          auth_deferrable_resolved = false

          connection.unsafe_once(:connected, :update) do
            auth_deferrable_resolved = true
            authorize_method_deferrable.succeed token
          end
          connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
            auth_deferrable_resolved = true
            authorize_method_deferrable.fail state_change.reason
          end
        end

        # Authorize failed, likely due to auth_url or auth_callback failing
        auth_operation.errback do |error|
          client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
          authorize_method_deferrable.fail error
        end
      end

      # Call the block provided to this method upon success of this deferrable
      authorize_method_deferrable.callback do |token|
        yield token if block_given?
      end
    end
  end

  # @deprecated Use {#authorize} instead
  def authorise(*args, &block)
    logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
    authorize(*args, &block)
  end

  # Synchronous version of {#authorize}. See {Ably::Auth#authorize} for method definition
  # Please note that authorize_sync will however not upgrade the current connection's token as this requires
  # an synchronous operation to send the new authentication details to Ably over a realtime connection
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def authorize_sync(token_params = nil, auth_options = nil)
    @authorization_in_flight = true
    auth_sync.authorize(token_params, auth_options)
  ensure
    @authorization_in_flight = false
  end

  # @api private
  def authorization_in_flight?
    @authorization_in_flight
  end

  # @deprecated Use {#authorize_sync} instead
  def authorise_sync(*args)
    logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
    authorize_sync(*args)
  end

  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
  #
  # @param (see Ably::Auth#request_token)
  # @option (see Ably::Auth#request_token)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.request_token do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def request_token(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      request_token_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def request_token_sync(token_params = {}, auth_options = {})
    auth_sync.request_token(token_params, auth_options)
  end

  # Creates and signs a token request that can then subsequently be used by any client to request a token
  #
  # @param (see Ably::Auth#create_token_request)
  # @option (see Ably::Auth#create_token_request)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Models::TokenRequest]
  #
  # @example
  #   client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
  #     token_request #=> Ably::Models::TokenRequest
  #   end
  def create_token_request(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      create_token_request_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenRequest]
  #
  def create_token_request_sync(token_params = {}, auth_options = {})
    auth_sync.create_token_request(token_params, auth_options)
  end

  # Auth header string used in HTTP requests to Ably
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header(&success_callback)
    async_wrap(success_callback) do
      auth_header_sync
    end
  end

  # Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
  # @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header_sync
    auth_sync.auth_header
  end

  def client_id_for_request_sync
    auth_sync.client_id_for_request
  end

  # Auth params used in URI endpoint for Realtime connections
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Hash] Auth params for a new Realtime connection
  #
  def auth_params(&success_callback)
    fail_callback = lambda do |error, deferrable|
      logger.error { "Failed to authenticate: #{error}" }
      if error.kind_of?(Ably::Exceptions::BaseAblyException)
        # Use base exception if it exists carrying forward the status codes
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
      else
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
      end
    end
    async_wrap(success_callback, fail_callback) do
      auth_params_sync
    end
  end

  # Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
  # @return [Hash] Auth params for a new Realtime connection
  #
  def auth_params_sync
    auth_sync.auth_params
  end

  private
  # The synchronous Auth class instanced by the Rest client
  # @return [Ably::Auth]
  def auth_sync
    @auth_sync
  end

  def client
    @client
  end

  # Sends an AUTH ProtocolMessage on the existing connection triggering
  # an inline AUTH process, see #RTC8a
  def perform_inline_auth(token)
    logger.debug { "Performing inline AUTH with Ably using token #{token}" }
    connection.send_protocol_message(
      action: Ably::Models::ProtocolMessage::ACTION.Auth.to_i,
      auth: { access_token: token.token }
    )
  end
end

#optionsObject (readonly)

Returns the value of attribute options.



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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ably/realtime/auth.rb', line 35

class Auth
  extend Forwardable
  include Ably::Modules::AsyncWrapper

  def_delegators :auth_sync, :client_id
  def_delegators :auth_sync, :token_client_id_allowed?, :configure_client_id, :client_id_validated?
  def_delegators :auth_sync, :can_assume_client_id?, :has_client_id?
  def_delegators :auth_sync, :current_token_details, :token
  def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
  def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
  def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
  def_delegators :client, :logger
  def_delegators :client, :connection

  def initialize(client)
    @client = client
    @auth_sync = client.rest_client.auth
  end

  # For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary.
  # If a connection is already established, the connection will be upgraded with a new token
  #
  # In the event that a new token request is made, the provided options are used
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # will issue a simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.authorize do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def authorize(token_params = nil, auth_options = nil, &success_callback)
    Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
      # Wrap the sync authorize method and wait for the result from the deferrable
      async_wrap do
        authorize_sync(token_params, auth_options)
      end.tap do |auth_operation|
        # Authorize operation succeeded and we have a new token, now let's perform inline authentication
        auth_operation.callback do |token|
          case connection.state.to_sym
          when :initialized, :disconnected, :suspended, :closed, :closing, :failed
            connection.connect
          when :connected
            perform_inline_auth token
          when :connecting
            # Fail all current connection attempts and try again with the new token, see #RTC8b
            connection.manager.release_and_establish_new_transport
          else
            logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
            authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
            next
          end

          # Indicate success or failure based on response from realtime, see #RTC8b1
          auth_deferrable_resolved = false

          connection.unsafe_once(:connected, :update) do
            auth_deferrable_resolved = true
            authorize_method_deferrable.succeed token
          end
          connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
            auth_deferrable_resolved = true
            authorize_method_deferrable.fail state_change.reason
          end
        end

        # Authorize failed, likely due to auth_url or auth_callback failing
        auth_operation.errback do |error|
          client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
          authorize_method_deferrable.fail error
        end
      end

      # Call the block provided to this method upon success of this deferrable
      authorize_method_deferrable.callback do |token|
        yield token if block_given?
      end
    end
  end

  # @deprecated Use {#authorize} instead
  def authorise(*args, &block)
    logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
    authorize(*args, &block)
  end

  # Synchronous version of {#authorize}. See {Ably::Auth#authorize} for method definition
  # Please note that authorize_sync will however not upgrade the current connection's token as this requires
  # an synchronous operation to send the new authentication details to Ably over a realtime connection
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def authorize_sync(token_params = nil, auth_options = nil)
    @authorization_in_flight = true
    auth_sync.authorize(token_params, auth_options)
  ensure
    @authorization_in_flight = false
  end

  # @api private
  def authorization_in_flight?
    @authorization_in_flight
  end

  # @deprecated Use {#authorize_sync} instead
  def authorise_sync(*args)
    logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
    authorize_sync(*args)
  end

  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
  #
  # @param (see Ably::Auth#request_token)
  # @option (see Ably::Auth#request_token)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.request_token do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def request_token(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      request_token_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def request_token_sync(token_params = {}, auth_options = {})
    auth_sync.request_token(token_params, auth_options)
  end

  # Creates and signs a token request that can then subsequently be used by any client to request a token
  #
  # @param (see Ably::Auth#create_token_request)
  # @option (see Ably::Auth#create_token_request)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Models::TokenRequest]
  #
  # @example
  #   client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
  #     token_request #=> Ably::Models::TokenRequest
  #   end
  def create_token_request(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      create_token_request_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenRequest]
  #
  def create_token_request_sync(token_params = {}, auth_options = {})
    auth_sync.create_token_request(token_params, auth_options)
  end

  # Auth header string used in HTTP requests to Ably
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header(&success_callback)
    async_wrap(success_callback) do
      auth_header_sync
    end
  end

  # Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
  # @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header_sync
    auth_sync.auth_header
  end

  def client_id_for_request_sync
    auth_sync.client_id_for_request
  end

  # Auth params used in URI endpoint for Realtime connections
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Hash] Auth params for a new Realtime connection
  #
  def auth_params(&success_callback)
    fail_callback = lambda do |error, deferrable|
      logger.error { "Failed to authenticate: #{error}" }
      if error.kind_of?(Ably::Exceptions::BaseAblyException)
        # Use base exception if it exists carrying forward the status codes
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
      else
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
      end
    end
    async_wrap(success_callback, fail_callback) do
      auth_params_sync
    end
  end

  # Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
  # @return [Hash] Auth params for a new Realtime connection
  #
  def auth_params_sync
    auth_sync.auth_params
  end

  private
  # The synchronous Auth class instanced by the Rest client
  # @return [Ably::Auth]
  def auth_sync
    @auth_sync
  end

  def client
    @client
  end

  # Sends an AUTH ProtocolMessage on the existing connection triggering
  # an inline AUTH process, see #RTC8a
  def perform_inline_auth(token)
    logger.debug { "Performing inline AUTH with Ably using token #{token}" }
    connection.send_protocol_message(
      action: Ably::Models::ProtocolMessage::ACTION.Auth.to_i,
      auth: { access_token: token.token }
    )
  end
end

#tokenObject (readonly)



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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ably/realtime/auth.rb', line 35

class Auth
  extend Forwardable
  include Ably::Modules::AsyncWrapper

  def_delegators :auth_sync, :client_id
  def_delegators :auth_sync, :token_client_id_allowed?, :configure_client_id, :client_id_validated?
  def_delegators :auth_sync, :can_assume_client_id?, :has_client_id?
  def_delegators :auth_sync, :current_token_details, :token
  def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
  def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
  def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
  def_delegators :client, :logger
  def_delegators :client, :connection

  def initialize(client)
    @client = client
    @auth_sync = client.rest_client.auth
  end

  # For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary.
  # If a connection is already established, the connection will be upgraded with a new token
  #
  # In the event that a new token request is made, the provided options are used
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # will issue a simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.authorize do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def authorize(token_params = nil, auth_options = nil, &success_callback)
    Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
      # Wrap the sync authorize method and wait for the result from the deferrable
      async_wrap do
        authorize_sync(token_params, auth_options)
      end.tap do |auth_operation|
        # Authorize operation succeeded and we have a new token, now let's perform inline authentication
        auth_operation.callback do |token|
          case connection.state.to_sym
          when :initialized, :disconnected, :suspended, :closed, :closing, :failed
            connection.connect
          when :connected
            perform_inline_auth token
          when :connecting
            # Fail all current connection attempts and try again with the new token, see #RTC8b
            connection.manager.release_and_establish_new_transport
          else
            logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
            authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
            next
          end

          # Indicate success or failure based on response from realtime, see #RTC8b1
          auth_deferrable_resolved = false

          connection.unsafe_once(:connected, :update) do
            auth_deferrable_resolved = true
            authorize_method_deferrable.succeed token
          end
          connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
            auth_deferrable_resolved = true
            authorize_method_deferrable.fail state_change.reason
          end
        end

        # Authorize failed, likely due to auth_url or auth_callback failing
        auth_operation.errback do |error|
          client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
          authorize_method_deferrable.fail error
        end
      end

      # Call the block provided to this method upon success of this deferrable
      authorize_method_deferrable.callback do |token|
        yield token if block_given?
      end
    end
  end

  # @deprecated Use {#authorize} instead
  def authorise(*args, &block)
    logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
    authorize(*args, &block)
  end

  # Synchronous version of {#authorize}. See {Ably::Auth#authorize} for method definition
  # Please note that authorize_sync will however not upgrade the current connection's token as this requires
  # an synchronous operation to send the new authentication details to Ably over a realtime connection
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def authorize_sync(token_params = nil, auth_options = nil)
    @authorization_in_flight = true
    auth_sync.authorize(token_params, auth_options)
  ensure
    @authorization_in_flight = false
  end

  # @api private
  def authorization_in_flight?
    @authorization_in_flight
  end

  # @deprecated Use {#authorize_sync} instead
  def authorise_sync(*args)
    logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
    authorize_sync(*args)
  end

  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
  #
  # @param (see Ably::Auth#request_token)
  # @option (see Ably::Auth#request_token)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.request_token do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def request_token(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      request_token_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def request_token_sync(token_params = {}, auth_options = {})
    auth_sync.request_token(token_params, auth_options)
  end

  # Creates and signs a token request that can then subsequently be used by any client to request a token
  #
  # @param (see Ably::Auth#create_token_request)
  # @option (see Ably::Auth#create_token_request)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Models::TokenRequest]
  #
  # @example
  #   client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
  #     token_request #=> Ably::Models::TokenRequest
  #   end
  def create_token_request(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      create_token_request_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenRequest]
  #
  def create_token_request_sync(token_params = {}, auth_options = {})
    auth_sync.create_token_request(token_params, auth_options)
  end

  # Auth header string used in HTTP requests to Ably
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header(&success_callback)
    async_wrap(success_callback) do
      auth_header_sync
    end
  end

  # Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
  # @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header_sync
    auth_sync.auth_header
  end

  def client_id_for_request_sync
    auth_sync.client_id_for_request
  end

  # Auth params used in URI endpoint for Realtime connections
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Hash] Auth params for a new Realtime connection
  #
  def auth_params(&success_callback)
    fail_callback = lambda do |error, deferrable|
      logger.error { "Failed to authenticate: #{error}" }
      if error.kind_of?(Ably::Exceptions::BaseAblyException)
        # Use base exception if it exists carrying forward the status codes
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
      else
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
      end
    end
    async_wrap(success_callback, fail_callback) do
      auth_params_sync
    end
  end

  # Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
  # @return [Hash] Auth params for a new Realtime connection
  #
  def auth_params_sync
    auth_sync.auth_params
  end

  private
  # The synchronous Auth class instanced by the Rest client
  # @return [Ably::Auth]
  def auth_sync
    @auth_sync
  end

  def client
    @client
  end

  # Sends an AUTH ProtocolMessage on the existing connection triggering
  # an inline AUTH process, see #RTC8a
  def perform_inline_auth(token)
    logger.debug { "Performing inline AUTH with Ably using token #{token}" }
    connection.send_protocol_message(
      action: Ably::Models::ProtocolMessage::ACTION.Auth.to_i,
      auth: { access_token: token.token }
    )
  end
end

#token_paramsObject (readonly)

Returns the value of attribute options.



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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ably/realtime/auth.rb', line 35

class Auth
  extend Forwardable
  include Ably::Modules::AsyncWrapper

  def_delegators :auth_sync, :client_id
  def_delegators :auth_sync, :token_client_id_allowed?, :configure_client_id, :client_id_validated?
  def_delegators :auth_sync, :can_assume_client_id?, :has_client_id?
  def_delegators :auth_sync, :current_token_details, :token
  def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
  def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
  def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
  def_delegators :client, :logger
  def_delegators :client, :connection

  def initialize(client)
    @client = client
    @auth_sync = client.rest_client.auth
  end

  # For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary.
  # If a connection is already established, the connection will be upgraded with a new token
  #
  # In the event that a new token request is made, the provided options are used
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # will issue a simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.authorize do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def authorize(token_params = nil, auth_options = nil, &success_callback)
    Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
      # Wrap the sync authorize method and wait for the result from the deferrable
      async_wrap do
        authorize_sync(token_params, auth_options)
      end.tap do |auth_operation|
        # Authorize operation succeeded and we have a new token, now let's perform inline authentication
        auth_operation.callback do |token|
          case connection.state.to_sym
          when :initialized, :disconnected, :suspended, :closed, :closing, :failed
            connection.connect
          when :connected
            perform_inline_auth token
          when :connecting
            # Fail all current connection attempts and try again with the new token, see #RTC8b
            connection.manager.release_and_establish_new_transport
          else
            logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
            authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
            next
          end

          # Indicate success or failure based on response from realtime, see #RTC8b1
          auth_deferrable_resolved = false

          connection.unsafe_once(:connected, :update) do
            auth_deferrable_resolved = true
            authorize_method_deferrable.succeed token
          end
          connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
            auth_deferrable_resolved = true
            authorize_method_deferrable.fail state_change.reason
          end
        end

        # Authorize failed, likely due to auth_url or auth_callback failing
        auth_operation.errback do |error|
          client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
          authorize_method_deferrable.fail error
        end
      end

      # Call the block provided to this method upon success of this deferrable
      authorize_method_deferrable.callback do |token|
        yield token if block_given?
      end
    end
  end

  # @deprecated Use {#authorize} instead
  def authorise(*args, &block)
    logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
    authorize(*args, &block)
  end

  # Synchronous version of {#authorize}. See {Ably::Auth#authorize} for method definition
  # Please note that authorize_sync will however not upgrade the current connection's token as this requires
  # an synchronous operation to send the new authentication details to Ably over a realtime connection
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def authorize_sync(token_params = nil, auth_options = nil)
    @authorization_in_flight = true
    auth_sync.authorize(token_params, auth_options)
  ensure
    @authorization_in_flight = false
  end

  # @api private
  def authorization_in_flight?
    @authorization_in_flight
  end

  # @deprecated Use {#authorize_sync} instead
  def authorise_sync(*args)
    logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
    authorize_sync(*args)
  end

  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
  #
  # @param (see Ably::Auth#request_token)
  # @option (see Ably::Auth#request_token)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.request_token do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def request_token(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      request_token_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def request_token_sync(token_params = {}, auth_options = {})
    auth_sync.request_token(token_params, auth_options)
  end

  # Creates and signs a token request that can then subsequently be used by any client to request a token
  #
  # @param (see Ably::Auth#create_token_request)
  # @option (see Ably::Auth#create_token_request)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Models::TokenRequest]
  #
  # @example
  #   client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
  #     token_request #=> Ably::Models::TokenRequest
  #   end
  def create_token_request(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      create_token_request_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenRequest]
  #
  def create_token_request_sync(token_params = {}, auth_options = {})
    auth_sync.create_token_request(token_params, auth_options)
  end

  # Auth header string used in HTTP requests to Ably
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header(&success_callback)
    async_wrap(success_callback) do
      auth_header_sync
    end
  end

  # Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
  # @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header_sync
    auth_sync.auth_header
  end

  def client_id_for_request_sync
    auth_sync.client_id_for_request
  end

  # Auth params used in URI endpoint for Realtime connections
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Hash] Auth params for a new Realtime connection
  #
  def auth_params(&success_callback)
    fail_callback = lambda do |error, deferrable|
      logger.error { "Failed to authenticate: #{error}" }
      if error.kind_of?(Ably::Exceptions::BaseAblyException)
        # Use base exception if it exists carrying forward the status codes
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
      else
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
      end
    end
    async_wrap(success_callback, fail_callback) do
      auth_params_sync
    end
  end

  # Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
  # @return [Hash] Auth params for a new Realtime connection
  #
  def auth_params_sync
    auth_sync.auth_params
  end

  private
  # The synchronous Auth class instanced by the Rest client
  # @return [Ably::Auth]
  def auth_sync
    @auth_sync
  end

  def client
    @client
  end

  # Sends an AUTH ProtocolMessage on the existing connection triggering
  # an inline AUTH process, see #RTC8a
  def perform_inline_auth(token)
    logger.debug { "Performing inline AUTH with Ably using token #{token}" }
    connection.send_protocol_message(
      action: Ably::Models::ProtocolMessage::ACTION.Auth.to_i,
      auth: { access_token: token.token }
    )
  end
end

#token_renewable?Boolean (readonly)

True if prerequisites for creating a new token request are present

One of the following criterion must be met:

  • Valid API key and token option not provided as token options cannot be determined

  • Authentication callback for new token requests

  • Authentication URL for new token requests

Returns:

  • (Boolean)


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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ably/realtime/auth.rb', line 35

class Auth
  extend Forwardable
  include Ably::Modules::AsyncWrapper

  def_delegators :auth_sync, :client_id
  def_delegators :auth_sync, :token_client_id_allowed?, :configure_client_id, :client_id_validated?
  def_delegators :auth_sync, :can_assume_client_id?, :has_client_id?
  def_delegators :auth_sync, :current_token_details, :token
  def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
  def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
  def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
  def_delegators :client, :logger
  def_delegators :client, :connection

  def initialize(client)
    @client = client
    @auth_sync = client.rest_client.auth
  end

  # For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary.
  # If a connection is already established, the connection will be upgraded with a new token
  #
  # In the event that a new token request is made, the provided options are used
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # will issue a simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.authorize do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def authorize(token_params = nil, auth_options = nil, &success_callback)
    Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
      # Wrap the sync authorize method and wait for the result from the deferrable
      async_wrap do
        authorize_sync(token_params, auth_options)
      end.tap do |auth_operation|
        # Authorize operation succeeded and we have a new token, now let's perform inline authentication
        auth_operation.callback do |token|
          case connection.state.to_sym
          when :initialized, :disconnected, :suspended, :closed, :closing, :failed
            connection.connect
          when :connected
            perform_inline_auth token
          when :connecting
            # Fail all current connection attempts and try again with the new token, see #RTC8b
            connection.manager.release_and_establish_new_transport
          else
            logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
            authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
            next
          end

          # Indicate success or failure based on response from realtime, see #RTC8b1
          auth_deferrable_resolved = false

          connection.unsafe_once(:connected, :update) do
            auth_deferrable_resolved = true
            authorize_method_deferrable.succeed token
          end
          connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
            auth_deferrable_resolved = true
            authorize_method_deferrable.fail state_change.reason
          end
        end

        # Authorize failed, likely due to auth_url or auth_callback failing
        auth_operation.errback do |error|
          client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
          authorize_method_deferrable.fail error
        end
      end

      # Call the block provided to this method upon success of this deferrable
      authorize_method_deferrable.callback do |token|
        yield token if block_given?
      end
    end
  end

  # @deprecated Use {#authorize} instead
  def authorise(*args, &block)
    logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
    authorize(*args, &block)
  end

  # Synchronous version of {#authorize}. See {Ably::Auth#authorize} for method definition
  # Please note that authorize_sync will however not upgrade the current connection's token as this requires
  # an synchronous operation to send the new authentication details to Ably over a realtime connection
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def authorize_sync(token_params = nil, auth_options = nil)
    @authorization_in_flight = true
    auth_sync.authorize(token_params, auth_options)
  ensure
    @authorization_in_flight = false
  end

  # @api private
  def authorization_in_flight?
    @authorization_in_flight
  end

  # @deprecated Use {#authorize_sync} instead
  def authorise_sync(*args)
    logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
    authorize_sync(*args)
  end

  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
  #
  # @param (see Ably::Auth#request_token)
  # @option (see Ably::Auth#request_token)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.request_token do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def request_token(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      request_token_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def request_token_sync(token_params = {}, auth_options = {})
    auth_sync.request_token(token_params, auth_options)
  end

  # Creates and signs a token request that can then subsequently be used by any client to request a token
  #
  # @param (see Ably::Auth#create_token_request)
  # @option (see Ably::Auth#create_token_request)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Models::TokenRequest]
  #
  # @example
  #   client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
  #     token_request #=> Ably::Models::TokenRequest
  #   end
  def create_token_request(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      create_token_request_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenRequest]
  #
  def create_token_request_sync(token_params = {}, auth_options = {})
    auth_sync.create_token_request(token_params, auth_options)
  end

  # Auth header string used in HTTP requests to Ably
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header(&success_callback)
    async_wrap(success_callback) do
      auth_header_sync
    end
  end

  # Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
  # @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header_sync
    auth_sync.auth_header
  end

  def client_id_for_request_sync
    auth_sync.client_id_for_request
  end

  # Auth params used in URI endpoint for Realtime connections
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Hash] Auth params for a new Realtime connection
  #
  def auth_params(&success_callback)
    fail_callback = lambda do |error, deferrable|
      logger.error { "Failed to authenticate: #{error}" }
      if error.kind_of?(Ably::Exceptions::BaseAblyException)
        # Use base exception if it exists carrying forward the status codes
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
      else
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
      end
    end
    async_wrap(success_callback, fail_callback) do
      auth_params_sync
    end
  end

  # Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
  # @return [Hash] Auth params for a new Realtime connection
  #
  def auth_params_sync
    auth_sync.auth_params
  end

  private
  # The synchronous Auth class instanced by the Rest client
  # @return [Ably::Auth]
  def auth_sync
    @auth_sync
  end

  def client
    @client
  end

  # Sends an AUTH ProtocolMessage on the existing connection triggering
  # an inline AUTH process, see #RTC8a
  def perform_inline_auth(token)
    logger.debug { "Performing inline AUTH with Ably using token #{token}" }
    connection.send_protocol_message(
      action: Ably::Models::ProtocolMessage::ACTION.Auth.to_i,
      auth: { access_token: token.token }
    )
  end
end

#using_basic_auth?Object (readonly)

True when Basic Auth is being used to authenticate with Ably



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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ably/realtime/auth.rb', line 35

class Auth
  extend Forwardable
  include Ably::Modules::AsyncWrapper

  def_delegators :auth_sync, :client_id
  def_delegators :auth_sync, :token_client_id_allowed?, :configure_client_id, :client_id_validated?
  def_delegators :auth_sync, :can_assume_client_id?, :has_client_id?
  def_delegators :auth_sync, :current_token_details, :token
  def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
  def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
  def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
  def_delegators :client, :logger
  def_delegators :client, :connection

  def initialize(client)
    @client = client
    @auth_sync = client.rest_client.auth
  end

  # For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary.
  # If a connection is already established, the connection will be upgraded with a new token
  #
  # In the event that a new token request is made, the provided options are used
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # will issue a simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.authorize do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def authorize(token_params = nil, auth_options = nil, &success_callback)
    Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
      # Wrap the sync authorize method and wait for the result from the deferrable
      async_wrap do
        authorize_sync(token_params, auth_options)
      end.tap do |auth_operation|
        # Authorize operation succeeded and we have a new token, now let's perform inline authentication
        auth_operation.callback do |token|
          case connection.state.to_sym
          when :initialized, :disconnected, :suspended, :closed, :closing, :failed
            connection.connect
          when :connected
            perform_inline_auth token
          when :connecting
            # Fail all current connection attempts and try again with the new token, see #RTC8b
            connection.manager.release_and_establish_new_transport
          else
            logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
            authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
            next
          end

          # Indicate success or failure based on response from realtime, see #RTC8b1
          auth_deferrable_resolved = false

          connection.unsafe_once(:connected, :update) do
            auth_deferrable_resolved = true
            authorize_method_deferrable.succeed token
          end
          connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
            auth_deferrable_resolved = true
            authorize_method_deferrable.fail state_change.reason
          end
        end

        # Authorize failed, likely due to auth_url or auth_callback failing
        auth_operation.errback do |error|
          client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
          authorize_method_deferrable.fail error
        end
      end

      # Call the block provided to this method upon success of this deferrable
      authorize_method_deferrable.callback do |token|
        yield token if block_given?
      end
    end
  end

  # @deprecated Use {#authorize} instead
  def authorise(*args, &block)
    logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
    authorize(*args, &block)
  end

  # Synchronous version of {#authorize}. See {Ably::Auth#authorize} for method definition
  # Please note that authorize_sync will however not upgrade the current connection's token as this requires
  # an synchronous operation to send the new authentication details to Ably over a realtime connection
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def authorize_sync(token_params = nil, auth_options = nil)
    @authorization_in_flight = true
    auth_sync.authorize(token_params, auth_options)
  ensure
    @authorization_in_flight = false
  end

  # @api private
  def authorization_in_flight?
    @authorization_in_flight
  end

  # @deprecated Use {#authorize_sync} instead
  def authorise_sync(*args)
    logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
    authorize_sync(*args)
  end

  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
  #
  # @param (see Ably::Auth#request_token)
  # @option (see Ably::Auth#request_token)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.request_token do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def request_token(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      request_token_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def request_token_sync(token_params = {}, auth_options = {})
    auth_sync.request_token(token_params, auth_options)
  end

  # Creates and signs a token request that can then subsequently be used by any client to request a token
  #
  # @param (see Ably::Auth#create_token_request)
  # @option (see Ably::Auth#create_token_request)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Models::TokenRequest]
  #
  # @example
  #   client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
  #     token_request #=> Ably::Models::TokenRequest
  #   end
  def create_token_request(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      create_token_request_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenRequest]
  #
  def create_token_request_sync(token_params = {}, auth_options = {})
    auth_sync.create_token_request(token_params, auth_options)
  end

  # Auth header string used in HTTP requests to Ably
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header(&success_callback)
    async_wrap(success_callback) do
      auth_header_sync
    end
  end

  # Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
  # @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header_sync
    auth_sync.auth_header
  end

  def client_id_for_request_sync
    auth_sync.client_id_for_request
  end

  # Auth params used in URI endpoint for Realtime connections
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Hash] Auth params for a new Realtime connection
  #
  def auth_params(&success_callback)
    fail_callback = lambda do |error, deferrable|
      logger.error { "Failed to authenticate: #{error}" }
      if error.kind_of?(Ably::Exceptions::BaseAblyException)
        # Use base exception if it exists carrying forward the status codes
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
      else
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
      end
    end
    async_wrap(success_callback, fail_callback) do
      auth_params_sync
    end
  end

  # Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
  # @return [Hash] Auth params for a new Realtime connection
  #
  def auth_params_sync
    auth_sync.auth_params
  end

  private
  # The synchronous Auth class instanced by the Rest client
  # @return [Ably::Auth]
  def auth_sync
    @auth_sync
  end

  def client
    @client
  end

  # Sends an AUTH ProtocolMessage on the existing connection triggering
  # an inline AUTH process, see #RTC8a
  def perform_inline_auth(token)
    logger.debug { "Performing inline AUTH with Ably using token #{token}" }
    connection.send_protocol_message(
      action: Ably::Models::ProtocolMessage::ACTION.Auth.to_i,
      auth: { access_token: token.token }
    )
  end
end

#using_token_auth?Object (readonly)

True when Token Auth is being used to authenticate with Ably



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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ably/realtime/auth.rb', line 35

class Auth
  extend Forwardable
  include Ably::Modules::AsyncWrapper

  def_delegators :auth_sync, :client_id
  def_delegators :auth_sync, :token_client_id_allowed?, :configure_client_id, :client_id_validated?
  def_delegators :auth_sync, :can_assume_client_id?, :has_client_id?
  def_delegators :auth_sync, :current_token_details, :token
  def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
  def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
  def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
  def_delegators :client, :logger
  def_delegators :client, :connection

  def initialize(client)
    @client = client
    @auth_sync = client.rest_client.auth
  end

  # For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary.
  # If a connection is already established, the connection will be upgraded with a new token
  #
  # In the event that a new token request is made, the provided options are used
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # will issue a simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.authorize do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def authorize(token_params = nil, auth_options = nil, &success_callback)
    Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
      # Wrap the sync authorize method and wait for the result from the deferrable
      async_wrap do
        authorize_sync(token_params, auth_options)
      end.tap do |auth_operation|
        # Authorize operation succeeded and we have a new token, now let's perform inline authentication
        auth_operation.callback do |token|
          case connection.state.to_sym
          when :initialized, :disconnected, :suspended, :closed, :closing, :failed
            connection.connect
          when :connected
            perform_inline_auth token
          when :connecting
            # Fail all current connection attempts and try again with the new token, see #RTC8b
            connection.manager.release_and_establish_new_transport
          else
            logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
            authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
            next
          end

          # Indicate success or failure based on response from realtime, see #RTC8b1
          auth_deferrable_resolved = false

          connection.unsafe_once(:connected, :update) do
            auth_deferrable_resolved = true
            authorize_method_deferrable.succeed token
          end
          connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
            auth_deferrable_resolved = true
            authorize_method_deferrable.fail state_change.reason
          end
        end

        # Authorize failed, likely due to auth_url or auth_callback failing
        auth_operation.errback do |error|
          client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
          authorize_method_deferrable.fail error
        end
      end

      # Call the block provided to this method upon success of this deferrable
      authorize_method_deferrable.callback do |token|
        yield token if block_given?
      end
    end
  end

  # @deprecated Use {#authorize} instead
  def authorise(*args, &block)
    logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
    authorize(*args, &block)
  end

  # Synchronous version of {#authorize}. See {Ably::Auth#authorize} for method definition
  # Please note that authorize_sync will however not upgrade the current connection's token as this requires
  # an synchronous operation to send the new authentication details to Ably over a realtime connection
  #
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def authorize_sync(token_params = nil, auth_options = nil)
    @authorization_in_flight = true
    auth_sync.authorize(token_params, auth_options)
  ensure
    @authorization_in_flight = false
  end

  # @api private
  def authorization_in_flight?
    @authorization_in_flight
  end

  # @deprecated Use {#authorize_sync} instead
  def authorise_sync(*args)
    logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
    authorize_sync(*args)
  end

  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
  #
  # @param (see Ably::Auth#request_token)
  # @option (see Ably::Auth#request_token)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Ably::Models::TokenDetails]
  #
  # @example
  #    # simple token request using basic auth
  #    client = Ably::Rest::Client.new(key: 'key.id:secret')
  #    client.auth.request_token do |token_details|
  #      token_details #=> Ably::Models::TokenDetails
  #    end
  #
  def request_token(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      request_token_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenDetails]
  #
  def request_token_sync(token_params = {}, auth_options = {})
    auth_sync.request_token(token_params, auth_options)
  end

  # Creates and signs a token request that can then subsequently be used by any client to request a token
  #
  # @param (see Ably::Auth#create_token_request)
  # @option (see Ably::Auth#create_token_request)
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Models::TokenRequest]
  #
  # @example
  #   client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
  #     token_request #=> Ably::Models::TokenRequest
  #   end
  def create_token_request(token_params = {}, auth_options = {}, &success_callback)
    async_wrap(success_callback) do
      create_token_request_sync(token_params, auth_options)
    end
  end

  # Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
  # @param (see Ably::Auth#authorize)
  # @option (see Ably::Auth#authorize)
  # @return [Ably::Models::TokenRequest]
  #
  def create_token_request_sync(token_params = {}, auth_options = {})
    auth_sync.create_token_request(token_params, auth_options)
  end

  # Auth header string used in HTTP requests to Ably
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header(&success_callback)
    async_wrap(success_callback) do
      auth_header_sync
    end
  end

  # Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
  # @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
  #
  def auth_header_sync
    auth_sync.auth_header
  end

  def client_id_for_request_sync
    auth_sync.client_id_for_request
  end

  # Auth params used in URI endpoint for Realtime connections
  # Will reauthorize implicitly if required and capable
  #
  # @return [Ably::Util::SafeDeferrable]
  # @yield [Hash] Auth params for a new Realtime connection
  #
  def auth_params(&success_callback)
    fail_callback = lambda do |error, deferrable|
      logger.error { "Failed to authenticate: #{error}" }
      if error.kind_of?(Ably::Exceptions::BaseAblyException)
        # Use base exception if it exists carrying forward the status codes
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
      else
        deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
      end
    end
    async_wrap(success_callback, fail_callback) do
      auth_params_sync
    end
  end

  # Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
  # @return [Hash] Auth params for a new Realtime connection
  #
  def auth_params_sync
    auth_sync.auth_params
  end

  private
  # The synchronous Auth class instanced by the Rest client
  # @return [Ably::Auth]
  def auth_sync
    @auth_sync
  end

  def client
    @client
  end

  # Sends an AUTH ProtocolMessage on the existing connection triggering
  # an inline AUTH process, see #RTC8a
  def perform_inline_auth(token)
    logger.debug { "Performing inline AUTH with Ably using token #{token}" }
    connection.send_protocol_message(
      action: Ably::Models::ProtocolMessage::ACTION.Auth.to_i,
      auth: { access_token: token.token }
    )
  end
end

Instance Method Details

#auth_header {|String| ... } ⇒ Ably::Util::SafeDeferrable

Auth header string used in HTTP requests to Ably Will reauthorize implicitly if required and capable

Yields:

  • (String)

    HTTP authentication value used in HTTP_AUTHORIZATION header

Returns:



216
217
218
219
220
# File 'lib/ably/realtime/auth.rb', line 216

def auth_header(&success_callback)
  async_wrap(success_callback) do
    auth_header_sync
  end
end

#auth_header_syncString

Synchronous version of #auth_header. See Auth#auth_header for method definition

Returns:

  • (String)

    HTTP authentication value used in HTTP_AUTHORIZATION header



225
226
227
# File 'lib/ably/realtime/auth.rb', line 225

def auth_header_sync
  auth_sync.auth_header
end

#auth_params {|Hash| ... } ⇒ Ably::Util::SafeDeferrable

Auth params used in URI endpoint for Realtime connections Will reauthorize implicitly if required and capable

Yields:

  • (Hash)

    Auth params for a new Realtime connection

Returns:



239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/ably/realtime/auth.rb', line 239

def auth_params(&success_callback)
  fail_callback = lambda do |error, deferrable|
    logger.error { "Failed to authenticate: #{error}" }
    if error.kind_of?(Ably::Exceptions::BaseAblyException)
      # Use base exception if it exists carrying forward the status codes
      deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
    else
      deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
    end
  end
  async_wrap(success_callback, fail_callback) do
    auth_params_sync
  end
end

#auth_params_syncHash

Synchronous version of #auth_params. See Auth#auth_params for method definition

Returns:

  • (Hash)

    Auth params for a new Realtime connection



257
258
259
# File 'lib/ably/realtime/auth.rb', line 257

def auth_params_sync
  auth_sync.auth_params
end

#authorise(*args, &block) ⇒ Object

Deprecated.

Use #authorize instead



122
123
124
125
# File 'lib/ably/realtime/auth.rb', line 122

def authorise(*args, &block)
  logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
  authorize(*args, &block)
end

#authorise_sync(*args) ⇒ Object

Deprecated.

Use #authorize_sync instead



148
149
150
151
# File 'lib/ably/realtime/auth.rb', line 148

def authorise_sync(*args)
  logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
  authorize_sync(*args)
end

#authorization_in_flight?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


143
144
145
# File 'lib/ably/realtime/auth.rb', line 143

def authorization_in_flight?
  @authorization_in_flight
end

#authorize(token_params = nil, auth_options = nil) {|Ably::Models::TokenDetails| ... } ⇒ Ably::Util::SafeDeferrable

For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary. If a connection is already established, the connection will be upgraded with a new token

In the event that a new token request is made, the provided options are used

Examples:

# will issue a simple token request using basic auth
client = Ably::Rest::Client.new(key: 'key.id:secret')
client.auth.authorize do |token_details|
  token_details #=> Ably::Models::TokenDetails
end

Parameters:

  • token_params (Hash, nil) (defaults to: nil)

    the token params used for future token requests. When nil, previously configured token params are used

  • auth_options (Hash, nil) (defaults to: nil)

    the authentication options used for future token requests. When nil, previously configure authentication options are used

Options Hash (token_params):

  • :client_id (String)

    A client ID to associate with this token. The generated token may be used to authenticate as this client_id

  • :ttl (Integer)

    validity time in seconds for the requested Models::TokenDetails. Limits may apply, see https://www.ably.com/docs/general/authentication

  • :capability (Hash)

    canonicalised representation of the resource paths and associated operations

  • :timestamp (Time)

    the time of the request

  • :nonce (String)

    an unquoted, unescaped random string of at least 16 characters

Options Hash (auth_options):

  • :auth_url (String)

    a URL to be used to GET or POST a set of token request params, to obtain a signed token request

  • :auth_headers (Hash)

    a set of application-specific headers to be added to any request made to the auth_url

  • :auth_params (Hash)

    a set of application-specific query params to be added to any request made to the auth_url

  • :auth_method (Symbol) — default: :get

    HTTP method to use with auth_url, must be either :get or :post

  • :auth_callback (Proc)

    when provided, the Proc will be called with the token params hash as the first argument, whenever a new token is required. The Proc should return a token string, Models::TokenDetails or JSON equivalent, Models::TokenRequest or JSON equivalent

  • :key (String)

    API key comprising the key name and key secret in a single string

  • :client_id (String)

    client ID identifying this connection to other clients (will use client_id specified when library was instanced if provided)

  • :query_time (Boolean)

    when true will query the Ably system for the current time instead of using the local time

  • :token_params (Hash)

    convenience to pass in token_params within the auth_options argument, especially useful when setting default token_params in the client constructor

Yields:

Returns:



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
117
118
119
# File 'lib/ably/realtime/auth.rb', line 72

def authorize(token_params = nil, auth_options = nil, &success_callback)
  Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
    # Wrap the sync authorize method and wait for the result from the deferrable
    async_wrap do
      authorize_sync(token_params, auth_options)
    end.tap do |auth_operation|
      # Authorize operation succeeded and we have a new token, now let's perform inline authentication
      auth_operation.callback do |token|
        case connection.state.to_sym
        when :initialized, :disconnected, :suspended, :closed, :closing, :failed
          connection.connect
        when :connected
          perform_inline_auth token
        when :connecting
          # Fail all current connection attempts and try again with the new token, see #RTC8b
          connection.manager.release_and_establish_new_transport
        else
          logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
          authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
          next
        end

        # Indicate success or failure based on response from realtime, see #RTC8b1
        auth_deferrable_resolved = false

        connection.unsafe_once(:connected, :update) do
          auth_deferrable_resolved = true
          authorize_method_deferrable.succeed token
        end
        connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
          auth_deferrable_resolved = true
          authorize_method_deferrable.fail state_change.reason
        end
      end

      # Authorize failed, likely due to auth_url or auth_callback failing
      auth_operation.errback do |error|
        client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
        authorize_method_deferrable.fail error
      end
    end

    # Call the block provided to this method upon success of this deferrable
    authorize_method_deferrable.callback do |token|
      yield token if block_given?
    end
  end
end

#authorize_sync(token_params = nil, auth_options = nil) ⇒ Ably::Models::TokenDetails

Synchronous version of #authorize. See Auth#authorize for method definition Please note that authorize_sync will however not upgrade the current connection’s token as this requires an synchronous operation to send the new authentication details to Ably over a realtime connection

Parameters:

  • token_params (Hash, nil) (defaults to: nil)

    the token params used for future token requests. When nil, previously configured token params are used

  • auth_options (Hash, nil) (defaults to: nil)

    the authentication options used for future token requests. When nil, previously configure authentication options are used

Options Hash (token_params):

  • :client_id (String)

    A client ID to associate with this token. The generated token may be used to authenticate as this client_id

  • :ttl (Integer)

    validity time in seconds for the requested Models::TokenDetails. Limits may apply, see https://www.ably.com/docs/general/authentication

  • :capability (Hash)

    canonicalised representation of the resource paths and associated operations

  • :timestamp (Time)

    the time of the request

  • :nonce (String)

    an unquoted, unescaped random string of at least 16 characters

Options Hash (auth_options):

  • :auth_url (String)

    a URL to be used to GET or POST a set of token request params, to obtain a signed token request

  • :auth_headers (Hash)

    a set of application-specific headers to be added to any request made to the auth_url

  • :auth_params (Hash)

    a set of application-specific query params to be added to any request made to the auth_url

  • :auth_method (Symbol) — default: :get

    HTTP method to use with auth_url, must be either :get or :post

  • :auth_callback (Proc)

    when provided, the Proc will be called with the token params hash as the first argument, whenever a new token is required. The Proc should return a token string, Models::TokenDetails or JSON equivalent, Models::TokenRequest or JSON equivalent

  • :key (String)

    API key comprising the key name and key secret in a single string

  • :client_id (String)

    client ID identifying this connection to other clients (will use client_id specified when library was instanced if provided)

  • :query_time (Boolean)

    when true will query the Ably system for the current time instead of using the local time

  • :token_params (Hash)

    convenience to pass in token_params within the auth_options argument, especially useful when setting default token_params in the client constructor

Returns:



135
136
137
138
139
140
# File 'lib/ably/realtime/auth.rb', line 135

def authorize_sync(token_params = nil, auth_options = nil)
  @authorization_in_flight = true
  auth_sync.authorize(token_params, auth_options)
ensure
  @authorization_in_flight = false
end

#client_id_for_request_syncObject



229
230
231
# File 'lib/ably/realtime/auth.rb', line 229

def client_id_for_request_sync
  auth_sync.client_id_for_request
end

#create_token_request(token_params = {}, auth_options = {}) {|Models::TokenRequest| ... } ⇒ Ably::Util::SafeDeferrable

Creates and signs a token request that can then subsequently be used by any client to request a token

Examples:

client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
  token_request #=> Ably::Models::TokenRequest
end

Parameters:

  • token_params (Hash) (defaults to: {})

    the token params used in the token request

  • auth_options (Hash) (defaults to: {})

    the authentication options for the token request

Options Hash (token_params):

  • :client_id (String)

    A client ID to associate with this token. The generated token may be used to authenticate as this client_id

  • :ttl (Integer)

    validity time in seconds for the requested Models::TokenDetails. Limits may apply, see https://www.ably.com/docs/general/authentication

  • :capability (Hash)

    canonicalised representation of the resource paths and associated operations

  • :timestamp (Time)

    the time of the request

  • :nonce (String)

    an unquoted, unescaped random string of at least 16 characters

Options Hash (auth_options):

  • :key (String)

    API key comprising the key name and key secret in a single string

  • :client_id (String)

    client ID identifying this connection to other clients (will use client_id specified when library was instanced if provided)

  • :query_time (Boolean)

    when true will query the Ably system for the current time instead of using the local time

  • :token_params (Hash)

    convenience to pass in token_params within the auth_options argument, especially useful when setting default token_params in the client constructor

Yields:

Returns:



195
196
197
198
199
# File 'lib/ably/realtime/auth.rb', line 195

def create_token_request(token_params = {}, auth_options = {}, &success_callback)
  async_wrap(success_callback) do
    create_token_request_sync(token_params, auth_options)
  end
end

#create_token_request_sync(token_params = {}, auth_options = {}) ⇒ Ably::Models::TokenRequest

Synchronous version of #create_token_request. See Auth#create_token_request for method definition

Parameters:

  • token_params (Hash, nil) (defaults to: {})

    the token params used for future token requests. When nil, previously configured token params are used

  • auth_options (Hash, nil) (defaults to: {})

    the authentication options used for future token requests. When nil, previously configure authentication options are used

Options Hash (token_params):

  • :client_id (String)

    A client ID to associate with this token. The generated token may be used to authenticate as this client_id

  • :ttl (Integer)

    validity time in seconds for the requested Models::TokenDetails. Limits may apply, see https://www.ably.com/docs/general/authentication

  • :capability (Hash)

    canonicalised representation of the resource paths and associated operations

  • :timestamp (Time)

    the time of the request

  • :nonce (String)

    an unquoted, unescaped random string of at least 16 characters

Options Hash (auth_options):

  • :auth_url (String)

    a URL to be used to GET or POST a set of token request params, to obtain a signed token request

  • :auth_headers (Hash)

    a set of application-specific headers to be added to any request made to the auth_url

  • :auth_params (Hash)

    a set of application-specific query params to be added to any request made to the auth_url

  • :auth_method (Symbol) — default: :get

    HTTP method to use with auth_url, must be either :get or :post

  • :auth_callback (Proc)

    when provided, the Proc will be called with the token params hash as the first argument, whenever a new token is required. The Proc should return a token string, Models::TokenDetails or JSON equivalent, Models::TokenRequest or JSON equivalent

  • :key (String)

    API key comprising the key name and key secret in a single string

  • :client_id (String)

    client ID identifying this connection to other clients (will use client_id specified when library was instanced if provided)

  • :query_time (Boolean)

    when true will query the Ably system for the current time instead of using the local time

  • :token_params (Hash)

    convenience to pass in token_params within the auth_options argument, especially useful when setting default token_params in the client constructor

Returns:



206
207
208
# File 'lib/ably/realtime/auth.rb', line 206

def create_token_request_sync(token_params = {}, auth_options = {})
  auth_sync.create_token_request(token_params, auth_options)
end

#request_token(token_params = {}, auth_options = {}) {|Ably::Models::TokenDetails| ... } ⇒ Ably::Util::SafeDeferrable

Request a Models::TokenDetails which can be used to make authenticated token based requests

Examples:

# simple token request using basic auth
client = Ably::Rest::Client.new(key: 'key.id:secret')
client.auth.request_token do |token_details|
  token_details #=> Ably::Models::TokenDetails
end

Parameters:

  • auth_options (Hash) (defaults to: {})

    (see #create_token_request)

  • token_params (Hash) (defaults to: {})

    (see #create_token_request)

Options Hash (token_params):

  • :client_id (String)

    A client ID to associate with this token. The generated token may be used to authenticate as this client_id

  • :ttl (Integer)

    validity time in seconds for the requested Models::TokenDetails. Limits may apply, see https://www.ably.com/docs/general/authentication

  • :capability (Hash)

    canonicalised representation of the resource paths and associated operations

  • :timestamp (Time)

    the time of the request

  • :nonce (String)

    an unquoted, unescaped random string of at least 16 characters

Options Hash (auth_options):

  • :auth_url (String)

    a URL to be used to GET or POST a set of token request params, to obtain a signed token request

  • :auth_headers (Hash)

    a set of application-specific headers to be added to any request made to the auth_url

  • :auth_params (Hash)

    a set of application-specific query params to be added to any request made to the auth_url

  • :auth_method (Symbol) — default: :get

    HTTP method to use with auth_url, must be either :get or :post

  • :auth_callback (Proc)

    when provided, the Proc will be called with the token params hash as the first argument, whenever a new token is required. The Proc should return a token string, Models::TokenDetails or JSON equivalent, Models::TokenRequest or JSON equivalent

  • :key (String)

    API key comprising the key name and key secret in a single string

  • :client_id (String)

    client ID identifying this connection to other clients (will use client_id specified when library was instanced if provided)

  • :query_time (Boolean)

    when true will query the Ably system for the current time instead of using the local time

  • :token_params (Hash)

    convenience to pass in token_params within the auth_options argument, especially useful when setting default token_params in the client constructor

Yields:

Returns:



168
169
170
171
172
# File 'lib/ably/realtime/auth.rb', line 168

def request_token(token_params = {}, auth_options = {}, &success_callback)
  async_wrap(success_callback) do
    request_token_sync(token_params, auth_options)
  end
end

#request_token_sync(token_params = {}, auth_options = {}) ⇒ Ably::Models::TokenDetails

Synchronous version of #request_token. See Auth#request_token for method definition

Parameters:

  • token_params (Hash, nil) (defaults to: {})

    the token params used for future token requests. When nil, previously configured token params are used

  • auth_options (Hash, nil) (defaults to: {})

    the authentication options used for future token requests. When nil, previously configure authentication options are used

Options Hash (token_params):

  • :client_id (String)

    A client ID to associate with this token. The generated token may be used to authenticate as this client_id

  • :ttl (Integer)

    validity time in seconds for the requested Models::TokenDetails. Limits may apply, see https://www.ably.com/docs/general/authentication

  • :capability (Hash)

    canonicalised representation of the resource paths and associated operations

  • :timestamp (Time)

    the time of the request

  • :nonce (String)

    an unquoted, unescaped random string of at least 16 characters

Options Hash (auth_options):

  • :auth_url (String)

    a URL to be used to GET or POST a set of token request params, to obtain a signed token request

  • :auth_headers (Hash)

    a set of application-specific headers to be added to any request made to the auth_url

  • :auth_params (Hash)

    a set of application-specific query params to be added to any request made to the auth_url

  • :auth_method (Symbol) — default: :get

    HTTP method to use with auth_url, must be either :get or :post

  • :auth_callback (Proc)

    when provided, the Proc will be called with the token params hash as the first argument, whenever a new token is required. The Proc should return a token string, Models::TokenDetails or JSON equivalent, Models::TokenRequest or JSON equivalent

  • :key (String)

    API key comprising the key name and key secret in a single string

  • :client_id (String)

    client ID identifying this connection to other clients (will use client_id specified when library was instanced if provided)

  • :query_time (Boolean)

    when true will query the Ably system for the current time instead of using the local time

  • :token_params (Hash)

    convenience to pass in token_params within the auth_options argument, especially useful when setting default token_params in the client constructor

Returns:



179
180
181
# File 'lib/ably/realtime/auth.rb', line 179

def request_token_sync(token_params = {}, auth_options = {})
  auth_sync.request_token(token_params, auth_options)
end