Repository: auth0/auth0-python
Pull request #222 (2020-06-29 18:43:19)

Add missing external_id property to the import users job
### Changes

The endpoint was missing the `external_id` property.

### References

Resolves `SDK-1625`

### Testing

- [x] This change adds unit test coverage
- [ ] This change adds integration test coverage
- [x] This change has been tested on the latest version of the platform/language or why not

### Checklist

- [x] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md)
- [x] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md)
- [x] All existing and new tests complete without errors



Patch:
diff --git a/auth0/v3/authentication/token_verifier.py b/auth0/v3/authentication/token_verifier.py
index 0e1e7aa..70a42ea 100644
--- a/auth0/v3/authentication/token_verifier.py
+++ b/auth0/v3/authentication/token_verifier.py
@@ -296,12 +296,6 @@ class TokenVerifier():
         if 'iat' not in payload or not isinstance(payload['iat'], int):
             raise TokenValidationError('Issued At (iat) claim must be a number present in the ID token')
 
-        iat_time = payload['iat'] - leeway
-        if now < iat_time:
-            raise TokenValidationError(
-                'Issued At (iat) claim error in the ID token; current time ({}) is '
-                'before issued at time ({})'.format(now, iat_time))
-
         # Nonce
         if nonce:
             if 'nonce' not in payload or not isinstance(payload['nonce'], (str, ustr)):
diff --git a/auth0/v3/management/jobs.py b/auth0/v3/management/jobs.py
index 6e9c0bb..aa7cde4 100644
--- a/auth0/v3/management/jobs.py
+++ b/auth0/v3/management/jobs.py
@@ -2,7 +2,6 @@ from .rest import RestClient
 
 
 class Jobs(object):
-
     """Auth0 jobs endpoints
 
     Args:
@@ -72,7 +71,7 @@ class Jobs(object):
         """
         return self.client.post(self._url('users-exports'), data=body)
 
-    def import_users(self, connection_id, file_obj, upsert=False, send_completion_email=True):
+    def import_users(self, connection_id, file_obj, upsert=False, send_completion_email=True, external_id=None):
         """Imports users to a connection from a file.
 
         Args:
@@ -91,12 +90,15 @@ class Jobs(object):
             send_completion_email (bool): When set to True, an email will be sent to notify the completion of this job.
                 When set to False, no email will be sent. Defaults to True.
 
+            external_id (str):  Customer-defined ID.
+
         See: https://auth0.com/docs/api/management/v2#!/Jobs/post_users_imports
         """
         return self.client.file_post(self._url('users-imports'),
                                      data={'connection_id': connection_id,
                                            'upsert': str(upsert).lower(),
-                                           'send_completion_email': str(send_completion_email).lower()},
+                                           'send_completion_email': str(send_completion_email).lower(),
+                                           'external_id': external_id},
                                      files={'users': file_obj})
 
     def send_verification_email(self, body):


Test patch:
diff --git a/auth0/v3/test/authentication/test_token_verifier.py b/auth0/v3/test/authentication/test_token_verifier.py
index 7d58b18..293f260 100644
--- a/auth0/v3/test/authentication/test_token_verifier.py
+++ b/auth0/v3/test/authentication/test_token_verifier.py
@@ -329,13 +329,6 @@ class TestTokenVerifier(unittest.TestCase):
         token = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL3Rva2Vucy10ZXN0LmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHwxMjM0NTY3ODkiLCJhdWQiOlsidG9rZW5zLXRlc3QtMTIzIiwiZXh0ZXJuYWwtdGVzdC05OTkiXSwiZXhwIjoxNTg3NzY1MzYxLCJub25jZSI6ImExYjJjM2Q0ZTUiLCJhenAiOiJ0b2tlbnMtdGVzdC0xMjMiLCJhdXRoX3RpbWUiOjE1ODc2Nzg5NjF9.CWW7mWUhiI-rramQ2dIGi7vBsOMmsouIg32IL9u2g4Dg3PV0C55R7dL6Jvf9hqaZXvx9Psrw0vLnOlhFztAC6LlQuq2eCaLYsDme36NxeYGC7CFXygvlU_eXD5IdNK35GriTfpG_b5hC7tl2glMmNQcZWlsIyKw7eq8o1POpqo0K2bCVjoyJkHL6WUpw6_08HPspmTL_Qd0km08z6zgvbl8Hpzk-tLmXqN7LjmuhEsjnIFphu-dGwcQsoY3RAomYxAFXAPYT8siEIf2w3zlIoUde-mujiMUtMD-Od7t7w36GO6Kubb9M9inVwPEg1yFKlFTXZBKXu91xmOmvMJ5Qfg"
         self.assert_fails_with_error(token, 'Issued At (iat) claim must be a number present in the ID token')
 
-    def test_fails_with_iat_invalid(self):
-        token = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL3Rva2Vucy10ZXN0LmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHwxMjM0NTY3ODkiLCJhdWQiOlsidG9rZW5zLXRlc3QtMTIzIiwiZXh0ZXJuYWwtdGVzdC05OTkiXSwiZXhwIjoxNTg3NzY1MzYxLCJpYXQiOjE1ODc3NjUzNjEsIm5vbmNlIjoiYTFiMmMzZDRlNSIsImF6cCI6InRva2Vucy10ZXN0LTEyMyIsImF1dGhfdGltZSI6MTU4NzY3ODk2MX0.hVFs3ix49ZIrUCr9EM4CrjYvwxemsHOqhZdjzOmy9suQOe8xG0NzEdlRcxuCt8Exdqrrd2lu4iPFqUgwudjMFZT5f-1YE9AdvLqqDyBRVRPu2dV5SP4QbO4OAjMvNq-yfoRQ4kEuIfBnz56l6imB-tNgfbSveOzHzTPapE6vSlVnI03jlDR91qoEpda1XCXreKhar4lsTNBsuAP6mA313DHaErvyhoBlsq3lEh7vXafFlegl5DMuEmNmzgAO3JO-mpn0J2nBfZOvUQIkf9ITs09zYrxE0fZ3M6J7tIhd13UvaJuNDXbfX1zzyhjAHqgmlkd25o2IZIBVC51NQv483g"
-        mocked_clock = MOCKED_CLOCK - DEFAULT_LEEWAY - 1
-        self.assert_fails_with_error(token,
-                                     'Issued At (iat) claim error in the ID token; current time ({}) is before issued at time (1587765301)'.format(
-                                         mocked_clock), clock=mocked_clock)
-
     def test_passes_when_nonce_missing_but_not_required(self):
         token = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL3Rva2Vucy10ZXN0LmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHwxMjM0NTY3ODkiLCJhdWQiOlsidG9rZW5zLXRlc3QtMTIzIiwiZXh0ZXJuYWwtdGVzdC05OTkiXSwiZXhwIjoxNTg3NzY1MzYxLCJpYXQiOjE1ODc1OTI1NjEsImF6cCI6InRva2Vucy10ZXN0LTEyMyIsImF1dGhfdGltZSI6MTU4NzY3ODk2MX0.L-DveLCDf4Te7x3JZmQ6rCkUQrenl1NFpHqKD8Fs-glhd2iyc-TYffk1M30T0-wBri-3tTgraDAjZAjXuwSk0gV_V5uKCHyIoSRphrC88aX8IeECteQpHa4KR15lbzA5JdVhJu7LuCZ2EFvdjHh5GiViLRWsTSHGUM-uqcMK0q2kWGvCEgfOIXqocnQiyCNITxfgMYJd38zOsVeP7HFf9riuFEQz65oER22o3xyIZ-ILSaU10n6Ob559Rbjc0NVKH4hrggRg8kG7cJCiXbRxXnzO_VM8LmRHhF56jh3ZSrO4bzQa5xv04bMbX6A77muMZD0vghsaslvpWerWbwaSQQ"
 
diff --git a/auth0/v3/test/management/test_jobs.py b/auth0/v3/test/management/test_jobs.py
index b30d780..e589019 100644
--- a/auth0/v3/test/management/test_jobs.py
+++ b/auth0/v3/test/management/test_jobs.py
@@ -65,21 +65,21 @@ class TestJobs(unittest.TestCase):
 
         mock_instance.file_post.assert_called_with(
             'https://domain/api/v2/jobs/users-imports',
-            data={'connection_id': '1234', 'upsert': 'false', 'send_completion_email': 'true'},
+            data={'connection_id': '1234', 'upsert': 'false', 'send_completion_email': 'true', 'external_id': None},
             files={'users': {}}
         )
 
-        j.import_users(connection_id='1234', file_obj={}, upsert=True, send_completion_email=False)
+        j.import_users(connection_id='1234', file_obj={}, upsert=True, send_completion_email=False, external_id="ext-id-123")
         mock_instance.file_post.assert_called_with(
             'https://domain/api/v2/jobs/users-imports',
-            data={'connection_id': '1234', 'upsert': 'true', 'send_completion_email': 'false'},
+            data={'connection_id': '1234', 'upsert': 'true', 'send_completion_email': 'false', 'external_id': 'ext-id-123'},
             files={'users': {}}
         )
 
         j.import_users(connection_id='1234', file_obj={}, upsert=False, send_completion_email=True)
         mock_instance.file_post.assert_called_with(
             'https://domain/api/v2/jobs/users-imports',
-            data={'connection_id': '1234', 'upsert': 'false', 'send_completion_email': 'true'},
+            data={'connection_id': '1234', 'upsert': 'false', 'send_completion_email': 'true', 'external_id': None},
             files={'users': {}}
         )