def _get_user_authentication_credentials(client_secret_file, scopes, credential_directory=None): """Returns user credentials.""" if credential_directory is None: credential_directory = os.getcwd() elif credential_directory == 'global': home_dir = os.path.expanduser('~') credential_directory = os.path.join(home_dir, '.credentials') if not os.path.exists(credential_directory): os.makedirs(credential_directory) else: pass credentials_path = os.path.join(credential_directory, 'sheets.googleapis.com-python.json') # TODO Change hardcoded name? if os.path.exists(credentials_path): # expect these to be valid. may expire at some point, but should be refreshed by google api client... return Credentials.from_authorized_user_file(credentials_path, scopes=scopes) flow = Flow.from_client_secrets_file(client_secret_file, scopes=scopes, redirect_uri='urn:ietf:wg:oauth:2.0:oob') auth_url, _ = flow.authorization_url(prompt='consent') print('Please go to this URL and finish the authentication flow: {}'.format(auth_url)) code = input('Enter the authorization code: ') flow.fetch_token(code=code) credentials = flow.credentials credentials_as_dict = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'id_token': credentials.id_token, 'token_uri': credentials.token_uri, 'client_id': credentials.client_id, 'client_secret': credentials.client_secret } with open(credentials_path, 'w') as file: file.write(json.dumps(credentials_as_dict)) return credentials
def main(): """Connects to Sheets API Checks whether column C = column A * column B as it should. """ creds = None # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( 'credentials.json', SCOPES) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open('token.json', 'w') as token: token.write(creds.to_json()) service = build('sheets', 'v4', credentials=creds) # Call the Sheets API # Search for sheet = service.spreadsheets() result = sheet.values().get(spreadsheetId=SAMPLE_SPREADSHEET_ID, range=SAMPLE_RANGE_NAME).execute() values = result.get('values', []) if not values: print('No data found.') else: print('Validating data ...') row_count = 2 for row in values: if int(row[2]) != (int(row[0]) * int(row[1])): print(f"Row {row_count} needs verification: " f"Found {row[2]}, expected {int(row[0]) * int(row[1])}") row_count += 1
def main() -> None: creds = None # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists(TOKEN_FILENAME): # Documentation: # - https://google-auth.readthedocs.io/en/stable/reference/google.oauth2.credentials.html creds = Credentials.from_authorized_user_file(TOKEN_FILENAME, SCOPES) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( CREDENTIALS_FILENAME, SCOPES) creds = flow.run_local_server(port=0) # Save the credentials for the next run. with open(TOKEN_FILENAME, "w") as token: token.write(creds.to_json()) service = build("sheets", "v4", credentials=creds) # Call the Sheets API. sheet = service.spreadsheets() result = (sheet.values().batchGet( spreadsheetId=os.getenv("SPREADSHEET_ID"), ranges=RANGES).execute()) values = result.get("valueRanges") weights = values[0].get("values") goals = values[1].get("values") weights_df = pd.DataFrame(weights[1:], columns=weights[0]) goals_df = pd.DataFrame(goals[1:], columns=goals[0]) weights_df.to_csv("data/weights.csv", index=False) goals_df.to_csv("data/goals.csv", index=False)
def gc_initialize(scopes, token_json_file, credentials_json_file, json_cred_dict): creds = None # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists(token_json_file): try: creds = Credentials.from_authorized_user_file( token_json_file, scopes) except: raise CalendarError("Failed to get credentials from .json file.") # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: try: creds.refresh(Request()) except: raise CalendarError("Unable to refresh token.") else: # Make sure credentials.json exists if not os.path.exists(credentials_json_file): print('Creating credentials.json file...') with open(credentials_json_file, 'w') as outfile: outfile.write(json.dumps(json_cred_dict)) outfile.close() print( 'Logging in to Google account... (if browser doesn\'t automatically open, ' 'go to the link below to log in)') flow = InstalledAppFlow.from_client_secrets_file( credentials_json_file, scopes) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open(token_json_file, 'w') as token: token.write(creds.to_json()) service = discovery.build('calendar', 'v3', credentials=creds) return service
def _dict_to_credentials(self, token): """ Convert old dict-style token. Does not preserve access token itself, assumes refresh required. """ try: token = service_account.Credentials.from_service_account_info( token, scopes=[self.scope] ) except: # noqa: E722 # TODO: catch specific exceptions token = Credentials( None, refresh_token=token["refresh_token"], client_secret=token["client_secret"], client_id=token["client_id"], token_uri="https://www.googleapis.com/oauth2/v4/token", scopes=[self.scope], ) return token
def connect(credentials_path='./credentials.json', token_path='./token.json'): creds = None # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists(token_path): creds = Credentials.from_authorized_user_file(token_path, SCOPES) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( credentials_path, SCOPES) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open(token_path, 'w') as token: token.write(creds.to_json()) return build('drive', 'v3', credentials=creds)
def get_conn(self): if self.conn is None: params = self.get_connection(self.gcp_conn_id) extra = params.extra_dejson logger = logging.getLogger() logging_level = logger.getEffectiveLevel() logger.setLevel(logging.ERROR) try: if 'authorized_user_file' in extra[ 'extra__google_cloud_platform__key_path']: creds = CredentialsUser.from_authorized_user_file( extra['extra__google_cloud_platform__key_path']) else: creds = Credentials.from_service_account_file( extra['extra__google_cloud_platform__key_path']) self.project_id = creds.project_id self.conn = storage.Client(credentials=creds, project=self.project_id) finally: logger.setLevel(logging_level) return self.conn
def build_service(self): """Get a service that communicates to a Google API. Returns: A service that is connected to the specified API. """ credentials = Credentials( token=self.token, refresh_token=self.refresh_token, id_token="", token_uri=self.token_uri, client_id=self.client_id, client_secret=self.client_secret, scopes=self.scopes, ) # Build the service object. service = build( serviceName=self.API_NAME, version=self.API_VERSION, credentials=credentials, ) return service
def upload_files(): oauth_config = config['oauth'] credentials = Credentials(None, refresh_token=oauth_config['refresh_token'], token_uri=oauth_config['token_uri'], client_id=get_ecredentials('yatch'), client_secret=get_ecredentials('bakery')) drive = build('drive', 'v3', credentials=credentials) media = MediaFileUpload('{0}.tar.gz'.format(config['timestamp'])) file_metadata = { 'name': ('{app_name}' + '-' + config['timestamp'] + '.tar.gz').format(**config), 'mimeType': 'application/gzip' } resp = drive.files().update(body=file_metadata, fileId=config['backup_file_id'], media_body=media).execute()
def service_account_login(): # If modifying these scopes, delete the file token.json. SCOPES = ["https://www.googleapis.com/auth/gmail.send"] creds = None # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists("token.json"): creds = Credentials.from_authorized_user_file("token.json", SCOPES) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file("credentials.json", SCOPES) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open("token.json", "w") as token: token.write(creds.to_json()) service = build("gmail", "v1", credentials=creds) return service
def get_creds(): creds = None # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: credentials_file = Path.home( ) / '.gcp_credentials' / 'credentials.json' flow = InstalledAppFlow.from_client_secrets_file( credentials_file.absolute().as_posix(), SCOPES) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open('token.json', 'w') as token: token.write(creds.to_json()) return creds
def main(): """get the file in terms of docx... """ creds = None # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) print(os.listdir()) drive = build('drive', 'v3', credentials=creds) request = drive.files().export_media(fileId='1aKf0ffoL7XjR26npjBmNcKClULSlGDIrlQx_E8dNXxI', mimeType='application/pdf') fh = io.BytesIO() downloader = MediaIoBaseDownload(fh, request) done = False while done is False: status, done = downloader.next_chunk() print("Download %d%%." % int(status.progress() * 100)) fh.seek(0) with open('PDFs/CV_mcdanal.pdf', 'wb') as f: # it's only been loaded into RAM! shutil.copyfileobj(fh, f, length=131072)
def drive_api() -> Resource: with locked_file(ref_tok_path) as f: ref_tok = f.read().strip() credentials = Credentials( None, refresh_token=ref_tok, token_uri="https://accounts.google.com/o/oauth2/token", client_id=client_id, client_secret=client_secret ) try: drive = build('drive', 'v3', credentials=credentials) except httplib2.ServerNotFoundError: print('httplib2 exception in drive build') sys.exit(1) except Exception as e: print(f'{e} exception in drive build') sys.exit(1) return drive
def youtube_auth(): print(settings.REFRESH_TOKEN) creds = Credentials( token=None, refresh_token=settings.REFRESH_TOKEN, token_uri="https://oauth2.googleapis.com/token", client_id=settings.CLIENT_ID, client_secret=settings.CLIENT_SECRET, ) api_service_name = "youtube" api_version = "v3" try: youtube = build( api_service_name, api_version, credentials=creds, cache_discovery=False ) return youtube except RefreshError as e: print(e) sys.exit(-1)
def get_inbox(): if 'credentials' not in session: session['scope'] = 'readonly' return redirect('authorize') credentials = Credentials(**session['credentials']) try: service = build('gmail', 'v1', credentials=credentials) results = service.users().getProfile(userId='me').execute() app.logger.info('Threading started') threading.Thread(target=mail_q_handler, daemon=True).start() app.logger.info('inserting to queue') mail_req_q.put(credentials, block=False) except HttpError as error: app.logger.error('An error occured:', error) return 'An error occured in getting profile' return jsonify(results)
def fetchCreds(self, config): creds = None # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file( 'token.json', config.scopes) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( 'credentials.json', config.scopes) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open('token.json', 'w') as token: token.write(creds.to_json()) self.creds = creds
def check_auth(): global secrets, path_token, device, creds url = 'https://oauth2.googleapis.com/token' headers = {'Content-type': 'application/x-www-form-urlencoded'} data = f'client_id={secrets["client_id"]}&client_secret={secrets["client_secret"]}&device_code={device["device_code"]}' data += '&grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code' r = requests.post(url=url, headers=headers, data=data) r_str = r.content r_json = json.loads(r_str) print(json.dumps(r_json)) if 'error' in r_json: time.sleep(device['interval']) check_auth() elif 'access_token' in r_json: creds = Credentials.from_authorized_user_file(path_client, SCOPES) creds.token = r_json f = open(path_token, "w") f.write(creds.to_json()) check_email() else: print(json.dumps(r_json))
def initGoogle(self): credentials = None # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists('token.json'): credentials = Credentials.from_authorized_user_file('token.json', self.SCOPES) # If there are no (valid) credentials available, let the user log in. if not credentials or not credentials.valid: if credentials and credentials.expired and credentials.refresh_token: credentials.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( 'credentials.json', self.SCOPES) credentials = flow.run_local_server(port=0) # Save the credentials for the next run with open('token.json', 'w') as token: token.write(credentials.to_json()) service = build('sheets', 'v4', credentials=credentials) self.sheet = service.spreadsheets()
def authenticate_google_calendar(): logger.info("Authenticating user to Google Calendar") credentials = None if os.path.exists('googleAPI/googleCalendar/secret_token.json'): logger.info("Secret Calendar token exists. User was found") credentials = Credentials.from_authorized_user_file('googleAPI/googleCalendar/secret_token.json', SCOPES) if not credentials or not credentials.valid: logger.info("Secret Calendar token does not exists. Redirecting user to Google") if credentials and credentials.expired and credentials.refresh_token: logger.info("Refreshing Google Calendar token") credentials.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( 'googleAPI/googleCalendar/credentials.json', SCOPES) credentials = flow.run_local_server(port=0) with open('googleAPI/googleCalendar/secret_token.json', 'w') as token: logger.info("Creating new Google Calendar token") token.write(credentials.to_json()) logger.info("New Google Calendar token was created successfully") google_calendar_service = build('calendar', 'v3', credentials=credentials) return google_calendar_service
def lambda_handler(event, context): s3 = boto3.client("s3") bucket = 'S3 Bucket Name' key = 'S3 Data File Name / Path' fileObj = s3.get_object(Bucket=bucket, Key=key) fileData = json.loads(fileObj["Body"].read().decode('utf-8')) creds = Credentials(token=fileData['access_token'], refresh_token=fileData['refresh_token'], client_id=fileData['client_id'], token_uri=fileData['token_uri'], client_secret=fileData['client_secret']) service = build('people', 'v1', credentials=creds, cache_discovery=False) contact2 = service.people().get(resourceName=event['contactid'],personFields=event['fields']).execute() return { 'statusCode': 200, 'body': 'Contact Data Retrieved Successfully', 'DATA': contact2 }
def refresh_token_service_object(self, refresh_token_file): with open(self.credentials_directory + "/" + refresh_token_file) as token_file, open( self.credentials_directory + "/" + self.client_secret_json) as secrets_file: refresh_token = token_file.read() client_secrets = json.loads(secrets_file.read()) credentials = Credentials( None, refresh_token=refresh_token, token_uri="https://accounts.google.com/o/oauth2/token", client_id=client_secrets["installed"]["client_id"], client_secret=client_secrets["installed"]["client_secret"]) service_object = build(self.api_name, self.api_version, credentials=credentials) return service_object
def get_temporary_bigtable_nodestorage() -> BigtableNodeStorage: if "BIGTABLE_EMULATOR_HOST" not in os.environ: pytest.skip( "Bigtable is not available, set BIGTABLE_EMULATOR_HOST enironment variable to enable" ) # The bigtable emulator requires _something_ to be passed as credentials, # even if they're totally bogus ones. ns = BigtableNodeStorage( project="test", credentials=Credentials.from_authorized_user_info( {key: "invalid" for key in ["client_id", "refresh_token", "client_secret"]} ), ) ns.bootstrap() try: yield ns finally: ns.store.destroy()
def set_client_credentials(client_cred_file): global creds if not client_cred_file: client_cred_file = SCRIPT_DIR_PATH + GOOGLE_API_CLIENT_CRED_FILE creds = None if os.path.exists(local_repo_path + TOKEN_FILE): creds = Credentials.from_authorized_user_file( local_repo_path + TOKEN_FILE, GOOGLE_API_SCOPES) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( client_cred_file, GOOGLE_API_SCOPES) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open(local_repo_path + TOKEN_FILE, 'w') as token: token.write(creds.to_json())
def __init__(self, cloud): """ Initialize GCP Manager object :param cloud: An object of class GcpCloud """ assert isinstance( cloud, GcpCloud ), "Invalid parameter 'cloud': Only GcpCloud type object allowed" self.credentials = None try: if cloud.gcp_credentials: self.credentials = Credentials( **cloud.gcp_credentials.to_json()) except (DefaultCredentialsError, RefreshError, TransportError): raise CloudAuthError(cloud.id) self.resource_management_operations = ResourceManagementOperations( cloud, self.credentials) self.compute_engine_operations = ComputeEngineOperations( cloud, self.credentials)
def get_credentials(): """Get the proper credentials needed to access my Google drive.""" creds = None # The TOKEN file stores the user's access and refresh tokens & is # created automatically when the authorization flow completes for the first time if osp.exists(DOCS_TOKEN_LOCATION): creds = Credentials.from_authorized_user_file(DOCS_TOKEN_LOCATION, DOCS_ACCESS_SCOPE) # if there are no (valid) credentials available, let the user log in if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( CREDENTIALS_FILE, DOCS_ACCESS_SCOPE) creds = flow.run_local_server(port=0) # save the credentials for the next run with open("token.json", 'w') as token: token.write(creds.to_json()) return creds
def get_authenticated_service(): if os.path.isfile("credentials.json"): with open("credentials.json", 'r') as f: creds_data = json.load(f) creds = Credentials(creds_data['token']) else: flow = InstalledAppFlow.from_client_secrets_file( CLIENT_SECRETS_FILE, SCOPES) creds = flow.run_console() creds_data = { 'token': creds.token, 'refresh_token': creds.refresh_token, 'token_uri': creds.token_uri, 'client_id': creds.client_id, 'client_secret': creds.client_secret, 'scopes': creds.scopes } with open("credentials.json", 'w') as outfile: json.dump(creds_data, outfile) return build(API_SERVICE_NAME, API_VERSION, credentials=creds)
def trip(): # helpers.handling_authorization() if not google.authorized: return redirect(url_for('google.login')) creds = Credentials(google.token['access_token']) print(google.token) http = AuthorizedHttp(creds) try: response = http.request( 'GET', 'https://people.googleapis.com/v1/people/me?personFields=names,emailAddresses' ) auth = helpers.handling_authorization(creds, response) return render_trip(auth) except Exception as e: print("Exception in auth:") print(repr(e)) return redirect(url_for('google.login'))
def main(): """Shows basic usage of the Drive Activity API. Prints information about the last 10 events that occured the user's Drive. """ creds = None # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( 'credentials.json', SCOPES) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open('token.json', 'w') as token: token.write(creds.to_json()) service = build('driveactivity', 'v2', credentials=creds) # Call the Drive Activity API results = service.activity().query(body={'pageSize': 10}).execute() activities = results.get('activities', []) if not activities: print('No activity.') else: print('Recent activity:') for activity in activities: time = getTimeInfo(activity) action = getActionInfo(activity['primaryActionDetail']) actors = map(getActorInfo, activity['actors']) targets = map(getTargetInfo, activity['targets']) print(u'{0}: {1}, {2}, {3}'.format(time, truncated(actors), action, truncated(targets)))
def __init__( self, key_path: Optional[str] = None, keyfile_dict: Optional[Dict[str, str]] = None, # See: https://github.com/PyCQA/pylint/issues/2377 scopes: Optional[Collection[str]] = None, # pylint: disable=unsubscriptable-object delegate_to: Optional[str] = None, disable_logging: bool = False, target_principal: Optional[str] = None, delegates: Optional[Sequence[str]] = None, ) -> None: super().__init__() if key_path and keyfile_dict: raise AirflowException( "The `keyfile_dict` and `key_path` fields are mutually exclusive. " "Please provide only one value." ) elif key_path.endswith('.token'): log.debug('Getting connection using Token key file %s', key_path) with open(key_path) as json_file: data = json.load(json_file) credentials = Credentials( token=data['access_token'], refresh_token=data['refresh_token'], token_uri=data['token_uri'], client_id=data['client_id'], client_secret=data['client_secret'], ) project_id = "hallowed-pipe-153306" self.key_path = key_path self.keyfile_dict = keyfile_dict self.scopes = scopes self.delegate_to = delegate_to self.disable_logging = disable_logging self.target_principal = target_principal self.delegates = delegates
def get_credentials(): """get_credentials""" from . import AUTH_SCOPES, CLIENT_SECRET_FILE, HEADLESS_AUTH, CREDENTIALS_FILE_NAME try: credentials = Credentials.from_authorized_user_file( CREDENTIALS_FILE_NAME) except FileNotFoundError: credentials = None except ValueError: credentials = None if credentials: return credentials try: flow = InstalledAppFlow.from_client_secrets_file( client_secrets_file=CLIENT_SECRET_FILE, scopes=AUTH_SCOPES) except FileNotFoundError: raise AuthError("Please provide a client secrete file as %r" % CLIENT_SECRET_FILE) if not HEADLESS_AUTH: credentials = flow.run_local_server() else: credentials = flow.run_console() creds_data = { "token": None, "refresh_token": credentials.refresh_token, "token_uri": credentials.token_uri, "client_id": credentials.client_id, "client_secret": credentials.client_secret, "scopes": credentials.scopes, } with open(CREDENTIALS_FILE_NAME, "w") as outfile: json.dump(creds_data, outfile) return credentials
def google_login(): creds = None # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( 'client_secret.json', SCOPES) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open('token.json', 'w') as token: token.write(creds.to_json()) GOOGLE_REVOKE_URI = "urn:ietf:wg:oauth:2.0:oob" auth_endpoint = 'https://accounts.google.com/o/oauth2/v2/auth' token_endpoint = 'https://www.googleapis.com/oauth2/v4/token' string = 'client_secret=' + creds.client_secret + '&grant_type=refresh_token&refresh_token=' + creds.refresh_token + '&client_id=' + creds.client_id result = requests.post('https://www.googleapis.com/oauth2/v4/token', string, headers={ 'Host': 'www.googleapis.com', 'Content-length': str(len(string)), 'content-type': 'application/x-www-form-urlencoded', 'user-agent': GOOGLE_REVOKE_URI }) result = result.json() global ACCESS_TOKEN ACCESS_TOKEN = result["access_token"] return