Skip to content

bookops_worldcat.authorize

Provides means to authenticate and authorize interactions with OCLC web services.

WorldcatAccessToken

WorldcatAccessToken(
    key: str,
    secret: str,
    scopes: str,
    agent: str = "",
    timeout: Union[
        int,
        float,
        Tuple[int, int],
        Tuple[float, float],
        None,
    ] = (5, 5),
)

Requests a WorldCat access token.

Authenticates and authorizes using Client Credentials Grant flow. A token with correctly bonded scopes can be passed into a session of an OCLC web service to authorize requests for resources.

Example
from bookops_worldcat import WorldcatAccessToken

token = WorldcatAccessToken(
    key="my_WSKey_client_id",
    secret="my_WSKey_secret",
    scopes="WorldCatMetadataAPI",
    agent="my_app/1.0.0")
print(token.token_str)
#>"tk_Yebz4BpEp9dAsghA7KpWx6dYD1OZKWBlHjqW"
print(token.is_expired())
#>False
print(token.server_response.json())
{
    "token_token": "tk_Yebz4BpEp9dAsghA7KpWx6dYD1OZKWBlHjqW",
    "token_type": "bearer",
    "expires_in": "1199",
    "principalID": "",
    "principalIDNS": "",
    "scopes": "WorldCatMetadataAPI",
    "contextInstitutionId": "00001",
    "expires_at": "2020-08-23 18:45:29Z"
}
print(token.server_response.request.headers)
{
    "User-Agent": "my_app/1.0.0",
    "Accept-Encoding": "gzip, deflate",
    "Accept": "application/json",
    "Connection": "keep-alive",
    "Content-Length": "67",
    "Content-Type": "application/x-www-form-urlencoded",
    "Authorization": "Basic encoded_authorization_here="
}
Usage Documentation:
PARAMETER DESCRIPTION
key

Your WSKey public client_id

TYPE: str

secret

Your WSKey secret

TYPE: str

scopes

Request scopes for the access token as a string. Multiple scopes should be separated with a space. Users with WSKeys set up to act on behalf of multiple institutions should provide scope and registryID in the format: {scope} context:{registryID}

EXAMPLES:

  • Single institution WSKey: "WorldCatMetadataAPI"
  • Multi-institution WSKey: "WorldCatMetadataAPI context:00001"

TYPE: str

agent

User-agent parameter to be passed in the request header. Usage is strongly encouraged.

TYPE: str DEFAULT: ''

timeout

How long to wait for server to send data before giving up. Accepts separate values for connect and read timeouts or a single value.

TYPE: Union[int, float, Tuple[int, int], Tuple[float, float], None] DEFAULT: (5, 5)

RAISES DESCRIPTION
TypeError

If agent, key, secret, or scopes args are passed anything other than a str.

ValueError

If an empty str is passed to key, secret or scopes arg.

WorldcatAuthorizationError

If request for token encounters any errors.

Source code in bookops_worldcat\authorize.py
 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
def __init__(
    self,
    key: str,
    secret: str,
    scopes: str,
    agent: str = "",
    timeout: Union[int, float, Tuple[int, int], Tuple[float, float], None] = (
        5,
        5,
    ),
) -> None:
    """Initializes WorldcatAccessToken object.


    info: Usage Documentation:
        - [Basic Usage](../start.md#authentication-and-authorization)
        - [Advanced Usage](../advanced.md#WorldcatAccessToken)

    Args:
        key:
            Your WSKey public client_id
        secret:
            Your WSKey secret
        scopes:
            Request scopes for the access token as a string. Multiple scopes
            should be separated with a space. Users with WSKeys set up to act on
            behalf of multiple institutions should provide scope and registryID
            in the format:
            `{scope} context:{registryID}`

            **EXAMPLES:**

            - Single institution WSKey: `"WorldCatMetadataAPI"`
            - Multi-institution WSKey: `"WorldCatMetadataAPI context:00001"`

        agent:
            `User-agent` parameter to be passed in the request header. Usage is
            strongly encouraged.
        timeout:
            How long to wait for server to send data before giving up. Accepts
            separate values for connect and read timeouts or a single value.

    Raises:
        TypeError:
            If `agent`, `key`, `secret`, or `scopes` args are passed
            anything other than a str.
        ValueError:
            If an empty str is passed to `key`, `secret` or `scopes` arg.
        WorldcatAuthorizationError:
            If request for token encounters any errors.
    """

    self.agent = agent
    self.grant_type = "client_credentials"
    self.key = key
    self.oauth_server = "https://oauth.oclc.org"
    self.scopes = scopes
    self.secret = secret
    self.server_response: Optional[requests.Response] = None
    self.timeout = timeout
    self.token_expires_at: Optional[datetime.datetime] = None
    self.token_str = ""
    self.token_type = ""

    # default bookops-worldcat request header
    if isinstance(self.agent, str):
        if not self.agent.strip():
            self.agent = f"{__title__}/{__version__}"
    else:
        raise TypeError("Argument 'agent' must be a string.")

    # ensure passed arguments are valid
    if isinstance(self.key, str):
        if not self.key.strip():
            raise ValueError("Argument 'key' cannot be an empty string.")
    else:
        raise TypeError("Argument 'key' must be a string.")

    if isinstance(self.secret, str):
        if not self.secret.strip():
            raise ValueError("Argument 'secret' cannot be an empty string.")
    else:
        raise TypeError("Argument 'secret' must be a string.")

    # validate passed scopes
    if isinstance(self.scopes, str):
        if not self.scopes.strip():
            raise ValueError("Argument 'scopes' cannot be an empty string.")
    else:
        raise TypeError("Argument 'scopes' must a string.")
    self.scopes = self.scopes.strip()

    # initiate request
    self._request_token()

is_expired

is_expired() -> bool

Checks if the access token is expired.

RETURNS DESCRIPTION
bool

Whether or not the token is expired.

TYPE: bool

RAISES DESCRIPTION
TypeError

If WorldcatAccessToken.token_expires_at is not a datetime.datetime object.

Example
token = WorldcatAccessToken(
    key="my_WSKey_client_id",
    secret="my_WSKey_secret",
    scopes="WorldCatMetadataAPI",
    agent="my_app/1.0.0")
print(token.is_expired())
#>False
Source code in bookops_worldcat\authorize.py
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
def is_expired(self) -> bool:
    """
    Checks if the access token is expired.

    Returns:
        bool: Whether or not the token is expired.

    Raises:
        TypeError:
            If `WorldcatAccessToken.token_expires_at` is not a
            `datetime.datetime` object.

    Example:
        ```py
        token = WorldcatAccessToken(
            key="my_WSKey_client_id",
            secret="my_WSKey_secret",
            scopes="WorldCatMetadataAPI",
            agent="my_app/1.0.0")
        print(token.is_expired())
        #>False
        ```
    """
    if isinstance(self.token_expires_at, datetime.datetime):
        if self.token_expires_at < datetime.datetime.now(datetime.timezone.utc):
            return True
        else:
            return False
    else:
        raise TypeError(
            "Attribute 'WorldcatAccessToken.token_expires_at' is of invalid type. "
            "Expected `datetime.datetime` object."
        )