Application Managed Sessions - OAuth2
If an application cannot or should not use a login session initiated by the
planet auth CLI command, the application will be
responsible for managing the process on its own, persisting session state as
needed.
Application managed sessions may be used with all authentication protocols.
Application developers may control whether sessions are visible to the CLI.
This is managed with the save_state_to_storage parameter on the planet.Auth
constructor methods illustrated below.
The process varies depending on the authentication protocol used.
Depending on the use case, applications may need to support multiple authentication
methods, just as the planet CLI command supports interacting with Planet APIs
using either a user or a service user account.
OAuth2 Session for Users
User session initialization inherently involves using a web browser to
complete user authentication. This architecture allows for greater security
by keeping the user's password from being directly exposed to the application
code. This also allows for flexibility in user federation and multifactor
authentication procedures without the complexity of these needing to
be exposed to the application developer who is focused on geospatial
operations using the Planet platform, and not the nuances of user
authentication and authorization.
OAuth2 User Client Registration
Developers of applications must register client applications with Planet, and
will be issued a Client ID as part of that process. Developers should register
a client for each distinct application so that end-users may discretely manage
applications permitted to access Planet APIs on their behalf.
See OAuth2 Client Registration
for more information.
With a Local Web Browser
In environments where a local browser is available, the Planet SDK library can manage
the process of launching the browser locally, transferring control to the Planet
authorization services for session initialization, and accepting a network
callback from the local browser to regain control once the authorization
process is complete. At a network protocol level, this establishes the user
login session using the OAuth2 authorization code flow.
To use this method using the SDK, the following requirements must be met:
- The application must be able to launch a local web browser.
- The web browser must be able to connect to Planet services.
- The application must be able to listen on a network port that is accessible
to the browser.
Examples - OAuth2 Authorization Code Flow
In Memory Session State
When an application cannot safely store user session state, it may operate purely in memory. When this
method is used, the user will be prompted to complete the login process each time the application is run.
Login as a user using a local browser with in memory only state persistance |
|---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 | import json
import planet
def example_main():
# Create an auth context with a client ID that
# is unique to this application.
plsdk_auth = planet.Auth.from_oauth_user_auth_code(
client_id="__MUST_BE_APP_DEVELOPER_SUPPLIED__",
requested_scopes=[
# Request access to Planet APIs
planet.PlanetOAuthScopes.PLANET,
# Request a refresh token so repeated browser logins are not required
planet.PlanetOAuthScopes.OFFLINE_ACCESS,
],
callback_url="http://localhost:8080",
save_state_to_storage=False,
)
# An application with no persistent storage must
# initialize a login every time. This is not smooth user experience.
plsdk_auth.user_login(allow_open_browser=True)
# Create a Planet SDK object that uses the loaded auth session.
sess = planet.Session(plsdk_auth)
pl = planet.Planet(sess)
# Use the SDK to call Planet APIs.
# Refreshing access tokens will be managed automatically by the SDK.
for item in pl.data.list_searches():
print(json.dumps(item, indent=2, sort_keys=True))
if __name__ == '__main__':
example_main()
|
Session State Shared with CLI
Applications may save their session state in a way that is shared with the CLI. With saved state,
the user will only be prompted to complete the login process once.
Login as a user using a local browser with sessions persisted on disk and shared with the CLI |
|---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 | import json
import planet
def example_main():
# Create an auth context with a client ID that
# is unique to this application.
plsdk_auth = planet.Auth.from_oauth_user_auth_code(
client_id="__MUST_BE_APP_DEVELOPER_SUPPLIED__",
requested_scopes=[
# Request access to Planet APIs
planet.PlanetOAuthScopes.PLANET,
# Request a refresh token so repeated browser logins are not required
planet.PlanetOAuthScopes.OFFLINE_ACCESS,
],
callback_url="http://localhost:8080",
profile_name="my-name-for-example-user-session-with-local-browser",
save_state_to_storage=True,
)
# In contrast to in-memory applications that must initialize a login every
# time, an app with persistent storage can skip user prompts when they
# are not needed.
# This helper will prompt the user only when it is necessary.
plsdk_auth.ensure_initialized(allow_open_browser=True,
allow_tty_prompt=True)
# Create a Planet SDK object that uses the loaded auth session.
sess = planet.Session(plsdk_auth)
pl = planet.Planet(sess)
# Use the SDK to call Planet APIs.
# Refreshing access tokens will be managed automatically by the SDK.
for item in pl.data.list_searches():
print(json.dumps(item, indent=2, sort_keys=True))
if __name__ == '__main__':
example_main()
|
Session State Saved to Application Storage
Applications may save their session state to application provided storage. With saved state,
the user should only be prompted to complete the login process once. Using application provided storage
will result in the session state not being shared with the CLI.
Applications needing to use their own storage will do so by providing
the Auth layer in the SDK with a custom implementation of the
planet_auth.ObjectStorageProvider
abstract base class. See examples below for more details.
Login as a user using a local browser with sessions persisted to application provided storage |
|---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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 | import json
import logging
import os
import pathlib
import stat
import planet
from planet_auth import ObjectStorageProvider, ObjectStorageProvider_KeyType
logging.basicConfig(level=logging.CRITICAL)
class DemoStorageProvider(ObjectStorageProvider):
"""
Simple demo custom storage provider that uses
~/.planet-demo as a storage home for saving object.
As a practical matter, ObjectStorageProvider_KeyType is defined
to be pathlib.Path, and we leverage that in this example.
But, storage providers are not required to use the local file
system to store objects.
"""
def __init__(self):
self._demo_storage_root = pathlib.Path.home() / ".planet-demo"
def load_obj(self, key: ObjectStorageProvider_KeyType) -> dict:
demo_obj_filepath = self._demo_obj_filepath(key)
return self._load_file(file_path=demo_obj_filepath)
def save_obj(self, key: ObjectStorageProvider_KeyType, data: dict) -> None:
demo_obj_filepath = self._demo_obj_filepath(key)
self._save_file(file_path=demo_obj_filepath, data=data)
def obj_exists(self, key: ObjectStorageProvider_KeyType) -> bool:
demo_obj_filepath = self._demo_obj_filepath(key)
return demo_obj_filepath.exists()
def mtime(self, key: ObjectStorageProvider_KeyType) -> float:
obj_filepath = self._demo_obj_filepath(key)
return obj_filepath.stat().st_mtime
def obj_rename(self,
src: ObjectStorageProvider_KeyType,
dst: ObjectStorageProvider_KeyType) -> None:
src_filepath = self._demo_obj_filepath(src)
dst_filepath = self._demo_obj_filepath(dst)
src_filepath.rename(dst_filepath)
def _demo_obj_filepath(self, obj_key):
if obj_key.is_absolute():
obj_path = self._demo_storage_root / obj_key.relative_to("/")
else:
obj_path = self._demo_storage_root / obj_key
return obj_path
@staticmethod
def _load_file(file_path: pathlib.Path) -> dict:
logging.debug(msg="Loading JSON data from file {}".format(file_path))
with open(file_path, mode="r", encoding="UTF-8") as file_r:
return json.load(file_r)
@staticmethod
def _save_file(file_path: pathlib.Path, data: dict):
file_path.parent.mkdir(parents=True, exist_ok=True)
logging.debug(msg="Writing JSON data to file {}".format(file_path))
with open(file_path, mode="w", encoding="UTF-8") as file_w:
os.chmod(file_path, stat.S_IREAD | stat.S_IWRITE)
_no_none_data = {
key: value
for key, value in data.items() if value is not None
}
file_w.write(json.dumps(_no_none_data, indent=2, sort_keys=True))
def example_main():
# Create an auth context with a client ID that
# is unique to this application.
plsdk_auth = planet.Auth.from_oauth_user_auth_code(
client_id="__MUST_BE_APP_DEVELOPER_SUPPLIED__",
requested_scopes=[
# Request access to Planet APIs
planet.PlanetOAuthScopes.PLANET,
# Request a refresh token so repeated browser logins are not required
planet.PlanetOAuthScopes.OFFLINE_ACCESS,
],
callback_url="http://localhost:8080",
profile_name="my-example-name-auth-code-with-custom-storage",
save_state_to_storage=True,
storage_provider=DemoStorageProvider(),
)
# In contrast to in-memory applications that must initialize a login every
# time, an app with persistent storage can skip user prompts when they
# are not needed.
# This helper will prompt the user only when it is necessary.
plsdk_auth.ensure_initialized(allow_open_browser=True,
allow_tty_prompt=True)
# Create a Planet SDK object that uses the loaded auth session.
sess = planet.Session(plsdk_auth)
pl = planet.Planet(sess)
# Use the SDK to call Planet APIs.
# Refreshing access tokens will be managed automatically by the SDK.
for item in pl.data.list_searches():
print(json.dumps(item, indent=2, sort_keys=True))
if __name__ == '__main__':
example_main()
|
Without a Local Web Browser
In environments where a local web browser is not available, additional steps must
be taken by the application author to initialize the user session.
For example, a remote shell to a cloud environment is not likely
to be able to open a browser on the user's desktop or receive network callbacks
from the user's desktop browser. In these cases, a browser is
still required. To complete login in such a case, the SDK will generate a URL and a
verification code that must be presented to the user. The user must visit the
URL out of band to complete the login process while the application polls for
the completion of the login process using the SDK. At a network protocol
level, this establishes the user login session using the OAuth2 device
code flow.
To use this method using the SDK, the following requirements must be met:
- The application must be able to connect to Planet services.
- The application must be able to display instructions to the user, directing
them to a web location to complete login.
As above, this may be done with state only persisted in memory, with state
shared with the CLI, or with state saved to application provided storage.
Examples - OAuth2 Device Code Flow
In Memory Session State
Login as a user using an external browser with in memory only state persistance |
|---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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 | import json
import planet
def initialize_user_session(plsdk_auth):
# Example of initiating a user session where the app is 100%
# responsible for the user experience.
# 1. Initiate the login
login_initialization_info = plsdk_auth.device_user_login_initiate()
# 2. Display necessary instructions to the user.
#
# "verification_uri" and "user_code" are required under RFC 8628.
# "verification_uri_complete" is optional under the RFC.
#
# If the user is expected to type in the URL, verification_uri will be
# shorter. If the URL may be presented in a clickable means (such as a
# link, button, or QR code) the verification_uri_complete may offer a
# better user experience.
verification_uri_complete = login_initialization_info.get(
"verification_uri_complete")
verification_uri = login_initialization_info.get("verification_uri")
user_code = login_initialization_info.get("user_code")
print("Please activate your client.")
if verification_uri_complete:
print(f"Visit the activation site:\n"
f"\n\t{verification_uri_complete}\n"
f"\nand confirm the authorization code:\n"
f"\n\t{user_code}\n")
else:
print(f"Visit the activation site:\n"
f"\n\t{verification_uri}\n"
f"\nand enter the authorization code:\n"
f"\n\t{user_code}\n")
# 3. Return control to the SDK. This will block until the user
# completes login.
plsdk_auth.device_user_login_complete(login_initialization_info)
def example_main():
# Create an auth context with a client ID that
# is unique to this application.
plsdk_auth = planet.Auth.from_oauth_user_device_code(
client_id="__MUST_BE_APP_DEVELOPER_SUPPLIED__",
requested_scopes=[
# Request access to Planet APIs
planet.PlanetOAuthScopes.PLANET,
# Request a refresh token so repeated browser logins are not required
planet.PlanetOAuthScopes.OFFLINE_ACCESS,
],
save_state_to_storage=False,
)
# An application with no persistent storage must initialize a login every
# time. This is not smooth user experience.
initialize_user_session(plsdk_auth)
# Create a Planet SDK object that uses the loaded auth session.
sess = planet.Session(plsdk_auth)
pl = planet.Planet(sess)
# Use the SDK to call Planet APIs.
# Refreshing access tokens will be managed automatically by the SDK.
for item in pl.data.list_searches():
print(json.dumps(item, indent=2, sort_keys=True))
if __name__ == '__main__':
example_main()
|
Session State Shared with CLI
Login as a user using an external browser with sessions persisted on disk and shared with the CLI |
|---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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 | import json
import planet
def initialize_user_session(plsdk_auth):
# Example of initiating a user session where the app is 100%
# responsible for the user experience.
# 1. Initiate the login
login_initialization_info = plsdk_auth.device_user_login_initiate()
# 2. Display necessary instructions to the user.
#
# "verification_uri" and "user_code" are required under RFC 8628.
# "verification_uri_complete" is optional under the RFC.
#
# If the user is expected to type in the URL, verification_uri will be
# shorter. If the URL may be presented in a clickable means (such as a
# link, button, or QR code) the verification_uri_complete may offer a
# better user experience.
verification_uri_complete = login_initialization_info.get(
"verification_uri_complete")
verification_uri = login_initialization_info.get("verification_uri")
user_code = login_initialization_info.get("user_code")
print("Please activate your client.")
if verification_uri_complete:
print(f"Visit the activation site:\n"
f"\n\t{verification_uri_complete}\n"
f"\nand confirm the authorization code:\n"
f"\n\t{user_code}\n")
else:
print(f"Visit the activation site:\n"
f"\n\t{verification_uri}\n"
f"\nand enter the authorization code:\n"
f"\n\t{user_code}\n")
# 3. Return control to the SDK. This will block until the user
# completes login.
plsdk_auth.device_user_login_complete(login_initialization_info)
def example_main():
# Create an auth context with a client ID that
# is unique to this application.
plsdk_auth = planet.Auth.from_oauth_user_device_code(
client_id="__MUST_BE_APP_DEVELOPER_SUPPLIED__",
requested_scopes=[
# Request access to Planet APIs
planet.PlanetOAuthScopes.PLANET,
# Request a refresh token so repeated browser logins are not required
planet.PlanetOAuthScopes.OFFLINE_ACCESS,
],
profile_name="my-name-example-user-auth-with-external-browser",
save_state_to_storage=True,
)
# In contrast to an in-memory only application that must initialize a login every
# time, an app with persistent storage can skip this when it is not needed.
if not plsdk_auth.is_initialized():
initialize_user_session(plsdk_auth)
# Create a Planet SDK object that uses the loaded auth session.
sess = planet.Session(plsdk_auth)
pl = planet.Planet(sess)
# Use the SDK to call Planet APIs.
# Refreshing access tokens will be managed automatically by the SDK.
for item in pl.data.list_searches():
print(json.dumps(item, indent=2, sort_keys=True))
if __name__ == '__main__':
example_main()
|
Session State Saved to Application Storage
Login as a user using an external browser with sessions persisted to application provided storage |
|---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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 | import json
import logging
import os
import pathlib
import stat
import planet
from planet_auth import ObjectStorageProvider, ObjectStorageProvider_KeyType
logging.basicConfig(level=logging.CRITICAL)
class DemoStorageProvider(ObjectStorageProvider):
"""
Simple demo custom storage provider that uses
~/.planet-demo as a storage home for saving object.
As a practical matter, ObjectStorageProvider_KeyType is defined
to be pathlib.Path, and we leverage that in this example.
But, storage providers are not required to use the local file
system to store objects.
"""
def __init__(self):
self._demo_storage_root = pathlib.Path.home() / ".planet-demo"
def load_obj(self, key: ObjectStorageProvider_KeyType) -> dict:
demo_obj_filepath = self._demo_obj_filepath(key)
return self._load_file(file_path=demo_obj_filepath)
def save_obj(self, key: ObjectStorageProvider_KeyType, data: dict) -> None:
demo_obj_filepath = self._demo_obj_filepath(key)
self._save_file(file_path=demo_obj_filepath, data=data)
def obj_exists(self, key: ObjectStorageProvider_KeyType) -> bool:
demo_obj_filepath = self._demo_obj_filepath(key)
return demo_obj_filepath.exists()
def mtime(self, key: ObjectStorageProvider_KeyType) -> float:
obj_filepath = self._demo_obj_filepath(key)
return obj_filepath.stat().st_mtime
def obj_rename(self,
src: ObjectStorageProvider_KeyType,
dst: ObjectStorageProvider_KeyType) -> None:
src_filepath = self._demo_obj_filepath(src)
dst_filepath = self._demo_obj_filepath(dst)
src_filepath.rename(dst_filepath)
def _demo_obj_filepath(self, obj_key):
if obj_key.is_absolute():
obj_path = self._demo_storage_root / obj_key.relative_to("/")
else:
obj_path = self._demo_storage_root / obj_key
return obj_path
@staticmethod
def _load_file(file_path: pathlib.Path) -> dict:
logging.debug(msg="Loading JSON data from file {}".format(file_path))
with open(file_path, mode="r", encoding="UTF-8") as file_r:
return json.load(file_r)
@staticmethod
def _save_file(file_path: pathlib.Path, data: dict):
file_path.parent.mkdir(parents=True, exist_ok=True)
logging.debug(msg="Writing JSON data to file {}".format(file_path))
with open(file_path, mode="w", encoding="UTF-8") as file_w:
os.chmod(file_path, stat.S_IREAD | stat.S_IWRITE)
_no_none_data = {
key: value
for key, value in data.items() if value is not None
}
file_w.write(json.dumps(_no_none_data, indent=2, sort_keys=True))
def initialize_user_session(plsdk_auth):
# Example of initiating a user session where the app is 100%
# responsible for the user experience.
# 1. Initiate the login
login_initialization_info = plsdk_auth.device_user_login_initiate()
# 2. Display necessary instructions to the user.
#
# "verification_uri" and "user_code" are required under RFC 8628.
# "verification_uri_complete" is optional under the RFC.
#
# If the user is expected to type in the URL, verification_uri will be
# shorter. If the URL may be presented in a clickable means (such as a
# link, button, or QR code) the verification_uri_complete may offer a
# better user experience.
verification_uri_complete = login_initialization_info.get(
"verification_uri_complete")
verification_uri = login_initialization_info.get("verification_uri")
user_code = login_initialization_info.get("user_code")
print("Please activate your client.")
if verification_uri_complete:
print(f"Visit the activation site:\n"
f"\n\t{verification_uri_complete}\n"
f"\nand confirm the authorization code:\n"
f"\n\t{user_code}\n")
else:
print(f"Visit the activation site:\n"
f"\n\t{verification_uri}\n"
f"\nand enter the authorization code:\n"
f"\n\t{user_code}\n")
# 3. Return control to the SDK. This will block until the user
# completes login.
plsdk_auth.device_user_login_complete(login_initialization_info)
def example_main():
# Create an auth context with a client ID that
# is unique to this application.
plsdk_auth = planet.Auth.from_oauth_user_device_code(
client_id="__MUST_BE_APP_DEVELOPER_SUPPLIED__",
requested_scopes=[
# Request access to Planet APIs
planet.PlanetOAuthScopes.PLANET,
# Request a refresh token so repeated browser logins are not required
planet.PlanetOAuthScopes.OFFLINE_ACCESS,
],
profile_name="my-example-name-device-code-with-custom-storage",
save_state_to_storage=True,
storage_provider=DemoStorageProvider(),
)
# In contrast to an in-memory only application that must initialize a login every
# time, an app with persistent storage can skip this when it is not needed.
if not plsdk_auth.is_initialized():
initialize_user_session(plsdk_auth)
# Create a Planet SDK object that uses the loaded auth session.
sess = planet.Session(plsdk_auth)
pl = planet.Planet(sess)
# Use the SDK to call Planet APIs.
# Refreshing access tokens will be managed automatically by the SDK.
for item in pl.data.list_searches():
print(json.dumps(item, indent=2, sort_keys=True))
if __name__ == '__main__':
example_main()
|
OAuth2 Session for Service Accounts
Service account session initialization is simpler than user session
initialization, and does not require a web browser.
While preserving session state for user sessions was a concern driven
in part by a concern for the user experience of using a web browser for
initialization, for service accounts it remains a concern to avoid
throttling by the authorization service.
If applications are expected to run longer than the life of an access token
(a few hours), then in memory operations are acceptable (for example: a long-running
data processing job). If application lifespan is short and frequent,
then the application should take steps to persist the session state (for
example: a command line utility run repeatedly from a shell with a short lifespan).
Like the session state itself, service account initialization parameters are
sensitive, and it is the responsibility of the application to store them
securely.
At a network protocol level, OAuth2 service account sessions are implemented
using the OAuth2 authorization code flow. This carries with it some additional
security concerns, discussed in
RFC 6819 ยง4.4.4.
Because of these considerations, service accounts should only be used for
workflows that are independent of a controlling user.
As above, this may be done with state only persisted in memory, with state
shared with the CLI, or with state saved to application provided storage.
OAuth2 M2M Client Registration
Service accounts are managed under the
OAuth Clients panel on the Planet Insights Account page.
See Sentinel Hub Authentication for further information.
Examples - OAuth2 Client Credentials Flow
In Memory Session State
Access APIs using a service account with in memory only state persistance |
|---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | import json
import planet
def example_main():
# Create an auth context with the client ID and secret of the service account.
plsdk_auth = planet.Auth.from_oauth_m2m(
client_id="__MUST_BE_END_USER_SUPPLIED__",
client_secret="__MUST_BE_END_USER_SUPPLIED__",
save_state_to_storage=False,
)
# Explicit login is not required for M2M client use. The above is sufficient.
# plsdk_auth.user_login()
# Create a Planet SDK object that uses the loaded auth session.
sess = planet.Session(plsdk_auth)
pl = planet.Planet(sess)
# Use the SDK to call Planet APIs.
# Refreshing access tokens will be managed automatically by the SDK.
for item in pl.data.list_searches():
print(json.dumps(item, indent=2, sort_keys=True))
if __name__ == '__main__':
example_main()
|
Session State Shared with CLI
Access APIs using a service account with sessions persisted on disk and shared with the CLI |
|---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | import json
import planet
def example_main():
# Create an auth context with the client ID and secret of the service account.
plsdk_auth = planet.Auth.from_oauth_m2m(
client_id="__MUST_BE_END_USER_SUPPLIED__",
client_secret="__MUST_BE_END_USER_SUPPLIED__",
profile_name="my-name-for-example-m2m-auth-profile",
save_state_to_storage=True,
)
# Explicit login is not required for M2M client use. The above is sufficient.
# plsdk_auth.user_login()
# Create a Planet SDK object that uses the loaded auth session.
sess = planet.Session(plsdk_auth)
pl = planet.Planet(sess)
# Use the SDK to call Planet APIs.
# Refreshing access tokens will be managed automatically by the SDK.
for item in pl.data.list_searches():
print(json.dumps(item, indent=2, sort_keys=True))
if __name__ == '__main__':
example_main()
|
Session State Saved to Application Storage
Access APIs using a service account with sessions persisted to application provided storage |
|---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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 | import json
import logging
import os
import pathlib
import stat
import planet
from planet_auth import ObjectStorageProvider, ObjectStorageProvider_KeyType
logging.basicConfig(level=logging.CRITICAL)
class DemoStorageProvider(ObjectStorageProvider):
"""
Simple demo custom storage provider that uses
~/.planet-demo as a storage home for saving object.
As a practical matter, ObjectStorageProvider_KeyType is defined
to be pathlib.Path, and we leverage that in this example.
But, storage providers are not required to use the local file
system to store objects.
"""
def __init__(self):
self._demo_storage_root = pathlib.Path.home() / ".planet-demo"
def load_obj(self, key: ObjectStorageProvider_KeyType) -> dict:
demo_obj_filepath = self._demo_obj_filepath(key)
return self._load_file(file_path=demo_obj_filepath)
def save_obj(self, key: ObjectStorageProvider_KeyType, data: dict) -> None:
demo_obj_filepath = self._demo_obj_filepath(key)
self._save_file(file_path=demo_obj_filepath, data=data)
def obj_exists(self, key: ObjectStorageProvider_KeyType) -> bool:
demo_obj_filepath = self._demo_obj_filepath(key)
return demo_obj_filepath.exists()
def mtime(self, key: ObjectStorageProvider_KeyType) -> float:
obj_filepath = self._demo_obj_filepath(key)
return obj_filepath.stat().st_mtime
def obj_rename(self,
src: ObjectStorageProvider_KeyType,
dst: ObjectStorageProvider_KeyType) -> None:
src_filepath = self._demo_obj_filepath(src)
dst_filepath = self._demo_obj_filepath(dst)
src_filepath.rename(dst_filepath)
def _demo_obj_filepath(self, obj_key):
if obj_key.is_absolute():
obj_path = self._demo_storage_root / obj_key.relative_to("/")
else:
obj_path = self._demo_storage_root / obj_key
return obj_path
@staticmethod
def _load_file(file_path: pathlib.Path) -> dict:
logging.debug(msg="Loading JSON data from file {}".format(file_path))
with open(file_path, mode="r", encoding="UTF-8") as file_r:
return json.load(file_r)
@staticmethod
def _save_file(file_path: pathlib.Path, data: dict):
file_path.parent.mkdir(parents=True, exist_ok=True)
logging.debug(msg="Writing JSON data to file {}".format(file_path))
with open(file_path, mode="w", encoding="UTF-8") as file_w:
os.chmod(file_path, stat.S_IREAD | stat.S_IWRITE)
_no_none_data = {
key: value
for key, value in data.items() if value is not None
}
file_w.write(json.dumps(_no_none_data, indent=2, sort_keys=True))
def example_main():
# Create an auth context with the client ID and secret of the service account.
plsdk_auth = planet.Auth.from_oauth_m2m(
client_id="__MUST_BE_END_USER_SUPPLIED__",
client_secret="__MUST_BE_END_USER_SUPPLIED__",
profile_name="my-example-name-m2m-with-custom-storage",
save_state_to_storage=True,
storage_provider=DemoStorageProvider(),
)
# Explicit login is not required for M2M client use. The above sufficient.
# plsdk_auth.user_login()
# Create a Planet SDK object that uses the loaded auth session.
sess = planet.Session(plsdk_auth)
pl = planet.Planet(sess)
# Use the SDK to call Planet APIs.
# Refreshing access tokens will be managed automatically by the SDK.
for item in pl.data.list_searches():
print(json.dumps(item, indent=2, sort_keys=True))
if __name__ == '__main__':
example_main()
|