Interface RequestAuthorizer

All Known Subinterfaces:
RequestAuthorizer.Proactive
All Known Implementing Classes:
OidcRequestAuthorizer

public interface RequestAuthorizer

Supplies the Authorization header of the requests an application sends to its own service, and renews it when the service refuses it.

An authorizer is given to one request with ConnectionRequest.setAuthorizer(RequestAuthorizer) or RequestBuilder.authorizer(RequestAuthorizer), or to every request under a base URL with NetworkManager.setAuthorizer(String, RequestAuthorizer):

NetworkManager.getInstance().setAuthorizer("https://api.example.com", authorizer);

OidcRequestAuthorizer is the implementation for a service that accepts OAuth 2.0 access tokens.

What happens to a request
  1. As the request is queued, getAuthorization(ConnectionRequest) is asked for a header value, which travels with the request. A request that already carries an Authorization header keeps its own: one the caller set always wins, and so does a default header of NetworkManager.
  2. If the service answers 401, nothing is delivered yet. The request is held and refreshAuthorization(ConnectionRequest, String) is asked for a new credential.
  3. If that succeeds the request is sent once more with the new header, and its answer -- whatever it is, another 401 included -- is delivered as usual. There is one renewal per request, so a service that keeps refusing cannot make this loop.
  4. If it fails, the request is sent again as it first was, and the service's 401 goes through the request's ordinary error handling exactly as it would have without an authorizer.

Code that waits for the request -- NetworkManager.addToQueueAndWait(ConnectionRequest), the blocking methods of RequestBuilder, NetworkManager.addToQueueAsync(ConnectionRequest) -- keeps waiting through all of it and sees only the final answer.

An authorizer that knows when its credential expires can skip the refused request altogether: see RequestAuthorizer.Proactive.

Threads

Every method of an authorizer is called on the event dispatch thread and on no other, so an implementation keeps its credential in plain fields and needs no lock. A network thread never calls one: it sends the header value that was put on the request, on the EDT, when the request was queued or released after a renewal. A request queued from another thread is passed to the EDT first, and so is a 401, which a network thread is the one to see.

The header is therefore the one current when the request was queued. If the credential is renewed while the request waits in the queue, the service refuses the old one and the request is sent again with the new one, as step 2 describes.

getAuthorization(ConnectionRequest) must answer from memory. It must not wait for another request: the EDT would wait on the queue it is filling. Renewing is therefore a separate step, which the authorizer starts and answers later.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Interface
    Description
    static interface 
    An authorizer that can tell, before a request is sent, that its credential is about to stop working, and renew it first.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final RequestAuthorizer
    An authorizer that never adds a header.
  • Method Summary

    Modifier and Type
    Method
    Description
    The value of the Authorization header for a request that is about to be sent, for example "Bearer eyJ...".
    refreshAuthorization(ConnectionRequest request, String rejectedAuthorization)
    Called after the service answered 401 to a request that carried this authorizer's header.
  • Field Details

  • Method Details

    • getAuthorization

      String getAuthorization(ConnectionRequest request)

      The value of the Authorization header for a request that is about to be sent, for example "Bearer eyJ...".

      Called on the event dispatch thread: when the request is queued, and again when it is sent a second time with a renewed credential. Answer from memory and do not block. The value is copied to the request; a redirect is sent the same one for as long as it stays under the base URL the authorizer was registered for.

      Parameters
      • request: the request being queued
      Returns

      the header value, or null to send the request without one

    • refreshAuthorization

      AsyncResource<Boolean> refreshAuthorization(ConnectionRequest request, String rejectedAuthorization)

      Called after the service answered 401 to a request that carried this authorizer's header. Called on the event dispatch thread, at most once per request.

      Several requests can be refused at the same moment. An implementation should renew its credential once and give every one of them the same answer, and should recognize a rejectedAuthorization that is no longer the current one: that request was sent before an earlier renewal finished, and only needs sending again.

      Parameters
      • request: the request that was refused

      • rejectedAuthorization: the header value the service refused

      Returns

      a resource that completes with true once a different credential is ready, and with false or an error when there is none to be had. Null means the same as false