Skip to content

Commit f08b89c

Browse files
authored
Merge pull request #1020 from kgrimes2/token-only-auth
Add support for authentication with Earthdata login token only Fixes #484
2 parents e61e253 + 6aac7d6 commit f08b89c

File tree

5 files changed

+42
-10
lines changed

5 files changed

+42
-10
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ and this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
3939
- `download` now returns Path consistently.
4040
([#595])(https://github.com/nsidc/earthaccess/issues/595)
4141
([@Sherwin-14](https://github.com/Sherwin-14))
42+
- Users may now authenticate with an existing Earthdata login token with
43+
environment variable `EARTHDATA_TOKEN`
44+
([#484](https://github.com/nsidc/earthaccess/issues/484))
45+
([@kgrimes2](https://github.com/kgrimes2))
4246

4347
### Removed
4448

docs/howto/authenticate.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ use:
3131
auth = earthaccess.login(strategy="environment")
3232
```
3333

34+
Alternatively, you can use an existing Earthdata Login token by setting the environment
35+
variable `EARTHDATA_TOKEN` to it and using the same "environment" strategy, above.
36+
3437
If you wish to enter your Earthdata Login credentials when prompted, with
3538
optional persistence to your `.netrc` file (see below), specify the interactive
3639
strategy:
@@ -54,7 +57,8 @@ credentials in two locations:
5457
used throughout documentation primarily for convenience. The only
5558
requirement is that the *contents* of the file adhere to the
5659
[`.netrc` file format](https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html).
57-
2. `EARTHDATA_USERNAME` and `EARTHDATA_PASSWORD` environment variables
60+
2. `EARTHDATA_USERNAME` and `EARTHDATA_PASSWORD` environment variables (or, optionally, `EARTHDATA_TOKEN`
61+
to use an existing Earthdata Login token)
5862

5963
If neither of these options are configured, you can authenticate by calling the
6064
`earthaccess.login()` method and manually entering your EDL account credentials.

earthaccess/api.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,9 @@ def login(
184184
* **"all"**: (default) try all methods until one works
185185
* **"interactive"**: enter username and password.
186186
* **"netrc"**: retrieve username and password from ~/.netrc.
187-
* **"environment"**: retrieve username and password from `$EARTHDATA_USERNAME` and `$EARTHDATA_PASSWORD`.
187+
* **"environment"**: retrieve either a username and password pair from
188+
the `EARTHDATA_USERNAME` and `EARTHDATA_PASSWORD` environment variables,
189+
or an Earthdata login token from the `EARTHDATA_TOKEN` environment variable.
188190
persist: will persist credentials in a .netrc file
189191
system: the Earthdata system to access, defaults to PROD
190192

earthaccess/auth.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,11 @@ def login(
110110
* **"interactive"**: Enter a username and password.
111111
* **"netrc"**: (default) Retrieve a username and password from ~/.netrc.
112112
* **"environment"**:
113-
Retrieve a username and password from $EARTHDATA_USERNAME and $EARTHDATA_PASSWORD.
114-
persist: Will persist credentials in a `.netrc` file.
113+
Retrieve either a username and password pair from the
114+
`EARTHDATA_USERNAME` and `EARTHDATA_PASSWORD` environment variables,
115+
or an Earthdata login token from the `EARTHDATA_TOKEN` environment
116+
variable.
117+
persist: Will persist username and password credentials in a `.netrc` file.
115118
system: the EDL endpoint to log in to Earthdata, defaults to PROD
116119
117120
Returns:
@@ -245,7 +248,7 @@ def _interactive(
245248
) -> bool:
246249
username = input("Enter your Earthdata Login username: ")
247250
password = getpass.getpass(prompt="Enter your Earthdata password: ")
248-
authenticated = self._get_credentials(username, password)
251+
authenticated = self._get_credentials(username, password, None)
249252
if authenticated:
250253
logger.debug("Using user provided credentials for EDL")
251254
if persist_credentials:
@@ -282,7 +285,7 @@ def _netrc(self) -> bool:
282285
f"Password not found in .netrc file {netrc_loc}"
283286
)
284287

285-
authenticated = self._get_credentials(username, password)
288+
authenticated = self._get_credentials(username, password, None)
286289

287290
if authenticated:
288291
logger.debug("Using .netrc file for EDL")
@@ -292,21 +295,27 @@ def _netrc(self) -> bool:
292295
def _environment(self) -> bool:
293296
username = os.getenv("EARTHDATA_USERNAME")
294297
password = os.getenv("EARTHDATA_PASSWORD")
298+
token = os.getenv("EARTHDATA_TOKEN")
295299

296-
if not username or not password:
300+
if (not username or not password) and not token:
297301
raise LoginStrategyUnavailable(
298-
"EARTHDATA_USERNAME and EARTHDATA_PASSWORD are not set in the current environment, try "
299-
"setting them or use a different strategy (netrc, interactive)"
302+
"Either the environment variables EARTHDATA_USERNAME and "
303+
"EARTHDATA_PASSWORD must both be set, or EARTHDATA_TOKEN must be set for "
304+
"the 'environment' login strategy."
300305
)
301306

302307
logger.debug("Using environment variables for EDL")
303-
return self._get_credentials(username, password)
308+
return self._get_credentials(username, password, token)
304309

305310
def _get_credentials(
306311
self,
307312
username: Optional[str],
308313
password: Optional[str],
314+
user_token: Optional[str],
309315
) -> bool:
316+
if user_token is not None:
317+
self.token = {"access_token": user_token}
318+
self.authenticated = True
310319
if username is not None and password is not None:
311320
token_resp = self._find_or_create_token(username, password)
312321

tests/unit/test_auth.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# package imports
22
import logging
3+
import os
34
import unittest
45
from unittest import mock
56

@@ -74,6 +75,18 @@ def test_auth_can_create_proper_credentials(self, user_input, user_password):
7475
self.assertEqual(auth.password, "password")
7576
self.assertEqual(auth.token, json_response)
7677

78+
@responses.activate
79+
def test_auth_can_parse_existing_user_token(self):
80+
user_token = "ABCDEFGHIJKLMNOPQ"
81+
os.environ["EARTHDATA_TOKEN"] = user_token
82+
json_response = {"access_token": user_token}
83+
84+
# Test
85+
auth = Auth()
86+
auth.login(strategy="environment")
87+
self.assertEqual(auth.authenticated, True)
88+
self.assertEqual(auth.token, json_response)
89+
7790
@responses.activate
7891
@mock.patch("getpass.getpass")
7992
@mock.patch("builtins.input")

0 commit comments

Comments
 (0)