Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breaking again - {"message":"HTTP 403 Forbidden","error":"ForbiddenException"} #103

Closed
app4g opened this issue Sep 26, 2023 · 21 comments
Closed

Comments

@app4g
Copy link

app4g commented Sep 26, 2023

Seems like it's breaking again...

garmin-get-activity --password password1 --log-level DEBUG [email protected] 12xxxxxxx fit
2023-09-26 16:59:47,883 [DEBUG] using session factory: cloudscraper
2023-09-26 16:59:47,903 [INFO] authenticating user ...
2023-09-26 16:59:47,903 [INFO] fetching CSRF token ...
2023-09-26 16:59:47,937 [DEBUG] Starting new HTTPS connection (1): sso.garmin.com:443
2023-09-26 16:59:48,394 [DEBUG] https://sso.garmin.com:443 "GET /sso/login?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&gauthHost=https%3A%2F%2Fsso.garmin.com%2Fsso HTTP/1.1" 200 None
2023-09-26 16:59:49,520 [DEBUG] https://sso.garmin.com:443 "POST /sso/signin?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&gauthHost=https%3A%2F%2Fsso.garmin.com%2Fsso HTTP/1.1" 200 None
2023-09-26 16:59:49,521 [DEBUG] got auth response:

<title>Success</title> <script type="text/javascript" src="/sso/js/jquery/3.1.1/jquery.min.js?20210319"></script> <script type="text/javascript">jQuery.noConflict();</script> <script type="text/javascript" src="/sso/js/json2.js"></script> <script type="text/javascript" src="/sso/js/consoleUtils.js?20210319"></script> <script type="text/javascript" src="/sso/js/postmessage.js?20210319"></script> <script type="text/javascript"> var redirectAfterAccountLoginUrl = ""; var redirectAfterAccountCreationUrl = ""; var consumeServiceTicket = "true"; var service_url = "https:\/\/connect.garmin.com\/modern\/"; var parent_url = ""; var response_url = "https:\/\/connect.garmin.com\/modern\/?ticket=ST-0357568-mLBwQntqJcj3ajh2biCW-cas"; var logintoken = ""; var socialLogin = ""; var performMFACheck = "";
		// Decode url if it's encoded unnecessarily (which is happening when SSO GAuth logins redisplay the login page due to session timeouts.)
		if (response_url.indexOf('%3A%2F%2F') != -1) {
			response_url = decodeURIComponent(response_url);
		}
		response_url = response_url.replace(new RegExp("&amp;", 'g'),"&");

		var service_ticket = response_url.substring(response_url.indexOf('ticket=') + 7, response_url.length);

		if (redirectAfterAccountLoginUrl) {
			consoleInfo('casEmbedSuccess.html: redirectAfterAccountLoginUrl: [' + redirectAfterAccountLoginUrl + ']');
		}
		consoleInfo('casEmbedSuccess.html: consumeServiceTicket:         [' + consumeServiceTicket + ']');
		consoleInfo('casEmbedSuccess.html: service_url:                  [' + service_url + ']');
		consoleInfo('casEmbedSuccess.html: parent_url:                   [' + parent_url + ']');
		consoleInfo('casEmbedSuccess.html: response_url:                 [' + response_url + ']');
		consoleInfo('casEmbedSuccess.html: service_ticket:               [' + service_ticket + ']');
		if (logintoken) {
			consoleInfo('casEmbedSuccess.html: logintoken:                   [' + logintoken + ']');
		}
		if (socialLogin) {
			consoleInfo('casEmbedSuccess.html: socialLogin:                   [' + socialLogin + ']');
		}

		function send(msg) {
			consoleInfo('casEmbedSuccess.html: send(): Calling XD.postMessage(msg:[' + JSON.stringify(msg) + '], target_url:[' + parent_url + '])...');
			XD.postMessage(msg, parent_url, parent);
			return false;
		}

		function redirect(target){
			var embedWidget = "";
			if (embedWidget != 'true') {
				if (logintoken || socialLogin) {
					//  Tell parent to close opened Gauth lite box.
					send({'closeLiteBox':'1'});
				} else {
					// Tell parent to resize Gauth widget's height to just that of the loading icon.
					send({'gauthHeight':jQuery("#GAuth-component").height()});
				}
			}

			if (window.opener != null) {
				var iframeParent = window.opener.parent;
				iframeParent.location.href = target;
				window.close();
			} else {
				// If the "redirectAfterAccountLoginUrl" GAuth config parameter was specified,
				// a full page refresh upon logon was requested, so redirect the parent window upon login.
				if (redirectAfterAccountLoginUrl || redirectAfterAccountCreationUrl || (socialLogin && socialLogin === 'true') || (performMFACheck && performMFACheck === 'true')) {

					if (embedWidget != 'true') {
						send({'status':'SUCCESS', 'successDetails':'Login Successful'});
					}

					// Redirect parent of login iframe to requested service URL with ?ST=<Service Ticket ID> appended,
					// so the webapp can validate the service ticket and log the user on to the webapp.
					consoleInfo('casEmbedSuccess.html: Calling parent.location.href = [' + response_url + '];...');
					top.location.href = response_url;

				// Else if GAuth was configured not to consume the service ticket, send the service ticket and service url.
				// It's then up to the parent page to hide the GAuth widget and validate the service ticket.
				} else if (consumeServiceTicket == 'false') {

					send({'status':'SUCCESS', 'successDetails':'Login Successful', 'serviceTicket':service_ticket, 'serviceUrl':service_url});

				} else {
					// Else consume the service ticket and log the user into the parent webapp, by making a JSONP request to the response url.
					// This service ticket request to the parent webapp will return a small amount of JSON that we
					// can send in the success event to the parent page to notify them of successful logon
					// It's then up to the parent page to hide the GAuth widget and do whatever it wants.
					consoleInfo('casEmbedSuccess.html: Loading ajax jsonp URL: [' + response_url + ']');
					jQuery.ajax({
						type: "REDIRECT",
						url: response_url,
						dataType: 'jsonp',
						error: function(xhr, status, error) {
							consoleError('casEmbedSuccess.html: Error loading ajax jsonp URL: [' + response_url + ']! Error: ' + error);
						},
						success: function( data, status, xhr ) {
							consoleInfo('casEmbedSuccess.html: success loading ajax jsonp url. data: [' + data + ']');
							var userdata = data;
							if (typeof(userdata) === 'string') {
								userdata = JSON.parse(data);
							}
							consoleInfo('casGenericRedirect.jsp: customerId: ['            + userdata.customerId
																		+ '], username: ['               + userdata.username
																		+ '], rememberMe: ['             + userdata.rememberMe
																		+ '], password: ['               + userdata.password
																		+ '], email: ['                  + userdata.email
																		+ '], displayName: ['            + userdata.displayName
																		+ '], firstName: ['              + userdata.firstName
																		+ '], lastName: ['               + userdata.lastName
																		+ '], localePreference: ['       + userdata.localePreference
																		+ '], addressLine1: ['           + userdata.addressLine1
																		+ '], addressLine2: ['           + userdata.addressLine2
																		+ '], cityName: ['               + userdata.cityName
																		+ '], state: ['                  + userdata.state
																		+ '], postalCode: ['             + userdata.postalCode
																		+ '], country: ['                + userdata.country
																		+ '], passwordChangeRequired: [' + userdata.passwordChangeRequired
																		+ '], lastLogin: ['              + userdata.lastLogin
																		+ '], erpCustomerNumber: ['      + userdata.erpCustomerNumber
																		+ ']');
							send({'status'                 : 'SUCCESS',
										'successDetails'         : 'Login Successful',
										'customerId'             : userdata.customerId,
										'username'               : userdata.username,
										'rememberMe'             : userdata.rememberMe,
										'password'               : userdata.password,
										'email'                  : userdata.email,
										'displayName'            : userdata.displayName,
										'firstName'              : userdata.firstName,
										'lastName'               : userdata.lastName,
										'localePreference'       : userdata.localePreference,
										'addressLine1'           : userdata.addressLine1,
										'addressLine2'           : userdata.addressLine2,
										'cityName'               : userdata.cityName,
										'state'                  : userdata.state,
										'postalCode'             : userdata.postalCode,
										'country'                : userdata.country,
										'passwordChangeRequired' : userdata.passwordChangeRequired,
										'lastLogin'              : userdata.lastLogin,
										'erpCustomerNumber'      : userdata.erpCustomerNumber
							});
						}
					});
				}
			}
		}
	</script>
</head>
<body>
	<div id="GAuth-component">
		<img src='/sso/images/ajax-loader.gif' class="loaderImage"/>
	</div>
	<script type="text/javascript">
		jQuery(document).ready(function(){
			var service = "https:\/\/connect.garmin.com\/modern\/";
			consoleInfo("casEmbedSuccess.html: ready, calling redirect('" + service + "')...");
			redirect(service);
		});
	</script>
<script>(function(){var js = "window['__CF$cv$params']={r:'80ca501c3a3713ea',t:'MTY5NTcxODc4OS41NzQwMDA='};_cpo=document.createElement('script');_cpo.nonce='',_cpo.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js',document.getElementsByTagName('head')[0].appendChild(_cpo);";var _0xh = document.createElement('iframe');_0xh.height = 1;_0xh.width = 1;_0xh.style.position = 'absolute';_0xh.style.top = 0;_0xh.style.left = 0;_0xh.style.border = 'none';_0xh.style.visibility = 'hidden';document.body.appendChild(_0xh);function handler() {var _0xi = _0xh.contentDocument || _0xh.contentWindow.document;if (_0xi) {var _0xj = _0xi.createElement('script');_0xj.innerHTML = js;_0xi.getElementsByTagName('head')[0].appendChild(_0xj);}}if (document.readyState !== 'loading') {handler();} else if (window.addEventListener) {document.addEventListener('DOMContentLoaded', handler);} else {var prev = document.onreadystatechange || function () {};document.onreadystatechange = function (e) {prev(e);if (document.readyState !== 'loading') {document.onreadystatechange = prev;handler();}};}})();</script></body>

2023-09-26 16:59:49,522 [DEBUG] auth ticket url: 'https://connect.garmin.com/modern/?ticket=ST-0357568-mLBwQntqJcj3ajh2biCW-cas'
2023-09-26 16:59:49,522 [INFO] claiming auth ticket ...
2023-09-26 16:59:49,524 [DEBUG] Starting new HTTPS connection (1): connect.garmin.com:443
2023-09-26 16:59:50,106 [DEBUG] https://connect.garmin.com:443 "GET /modern/?ticket=ST-0357568-mLBwQntqJcj3ajh2biCW-cas HTTP/1.1" 302 0
2023-09-26 16:59:50,373 [DEBUG] https://connect.garmin.com:443 "GET /modern/ HTTP/1.1" 302 0
2023-09-26 16:59:50,636 [DEBUG] https://connect.garmin.com:443 "GET /signin/?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F HTTP/1.1" 200 None
2023-09-26 16:59:50,904 [DEBUG] https://connect.garmin.com:443 "GET /modern HTTP/1.1" 302 0
2023-09-26 16:59:51,260 [DEBUG] https://sso.garmin.com:443 "GET /sso/login?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&webhost=https%3A%2F%2Fconnect.garmin.com&gateway=true&generateExtraServiceTicket=true&generateTwoExtraServiceTickets=true&clientId=GarminConnect HTTP/1.1" 302 0
2023-09-26 16:59:51,702 [DEBUG] https://connect.garmin.com:443 "GET /modern/ HTTP/1.1" 302 0
2023-09-26 16:59:51,974 [DEBUG] https://connect.garmin.com:443 "GET /signin/?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F HTTP/1.1" 200 None
2023-09-26 16:59:51,975 [INFO] fetching activity 12091532009 ...
2023-09-26 16:59:52,307 [DEBUG] https://connect.garmin.com:443 "GET /proxy/activity-service/activity/12091532009 HTTP/1.1" 403 None
2023-09-26 16:59:52,309 [ERROR] failed to fetch json summary for activity 12xxxxxxx: 403
{"message":"HTTP 403 Forbidden","error":"ForbiddenException"}
2023-09-26 16:59:52,309 [ERROR] failed with exception: failed to fetch json summary for activity 12xxxxxxx: 403
{"message":"HTTP 403 Forbidden","error":"ForbiddenException"}
Traceback (most recent call last):
File "/Users/username/.pyenv/versions/3.11.3/bin/garmin-get-activity", line 8, in
sys.exit(main())
^^^^^^
File "/Users/username/.pyenv/versions/3.11.3/lib/python3.11/site-packages/garminexport/cli/get_activity.py", line 68, in main
summary = client.get_activity_summary(args.activity)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/username/.pyenv/versions/3.11.3/lib/python3.11/site-packages/garminexport/garminclient.py", line 73, in check_session
return client_function(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/username/.pyenv/versions/3.11.3/lib/python3.11/site-packages/garminexport/garminclient.py", line 290, in get_activity_summary
raise Exception(u"failed to fetch json summary for activity {}: {}\n{}".format(
Exception: failed to fetch json summary for activity 12xxxxxxx: 403
{"message":"HTTP 403 Forbidden","error":"ForbiddenException"}

@mocquin
Copy link

mocquin commented Sep 26, 2023

Tonight was my first try at this package... getting similar error :

garmin-backup --log-level DEBUG [email protected]
2023-09-26 20:39:36,215 [INFO] backing up formats: json_summary, json_details, gpx, tcx, fit
Enter password: 
2023-09-26 20:39:42,322 [DEBUG] using session factory: requests.sessions
2023-09-26 20:39:42,323 [INFO] authenticating user ...
2023-09-26 20:39:42,323 [INFO] fetching CSRF token ...
2023-09-26 20:39:42,416 [DEBUG] Starting new HTTPS connection (1): sso.garmin.com:443
2023-09-26 20:39:43,160 [DEBUG] https://sso.garmin.com:443 "GET /sso/login?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&gauthHost=https%3A%2F%2Fsso.garmin.com%2Fsso HTTP/1.1" 200 None
2023-09-26 20:39:44,499 [DEBUG] https://sso.garmin.com:443 "POST /sso/signin?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&gauthHost=https%3A%2F%2Fsso.garmin.com%2Fsso HTTP/1.1" 200 None
2023-09-26 20:39:44,506 [DEBUG] got auth response: <!DOCTYPE html>
<html class="no-js">
        <head>
                <title>Success</title>
                <meta charset="utf-8">
                <meta http-equiv="X-UA-Compatible" content="IE=edge;" />
                <meta name="description" content="">
                <meta name="viewport" content="width=device-width, initial-scale=1">
                <meta http-equiv="cleartype" content="on">
                <script type="text/javascript" src="/sso/js/jquery/3.1.1/jquery.min.js?20210319"></script>
                <script type="text/javascript">jQuery.noConflict();</script>
                <script type="text/javascript" src="/sso/js/json2.js"></script>
                <script type="text/javascript" src="/sso/js/consoleUtils.js?20210319"></script>
                <script type="text/javascript" src="/sso/js/postmessage.js?20210319"></script>
                <script type="text/javascript">
                        var redirectAfterAccountLoginUrl          = "";
                        var redirectAfterAccountCreationUrl = "";
                        var consumeServiceTicket                  = "true";
                        var service_url                           = "https:\/\/connect.garmin.com\/modern\/";
                        var parent_url                            = "";
                        var response_url                          = "https:\/\/connect.garmin.com\/modern\/?ticket=ST-0405595-sr6Obth5ZKluqFlUJKCc-cas";
                        var logintoken                            = "";
                        var socialLogin                           = "";
                        var performMFACheck                 = "";

                        // Decode url if it's encoded unnecessarily (which is happening when SSO GAuth logins redisplay the login page due to session timeouts.)
                        if (response_url.indexOf('%3A%2F%2F') != -1) {
                                response_url = decodeURIComponent(response_url);
                        }
                        response_url = response_url.replace(new RegExp("&amp;", 'g'),"&");

                        var service_ticket = response_url.substring(response_url.indexOf('ticket=') + 7, response_url.length);

                        if (redirectAfterAccountLoginUrl) {
                                consoleInfo('casEmbedSuccess.html: redirectAfterAccountLoginUrl: [' + redirectAfterAccountLoginUrl + ']');
                        }
                        consoleInfo('casEmbedSuccess.html: consumeServiceTicket:         [' + consumeServiceTicket + ']');
                        consoleInfo('casEmbedSuccess.html: service_url:                  [' + service_url + ']');
                        consoleInfo('casEmbedSuccess.html: parent_url:                   [' + parent_url + ']');
                        consoleInfo('casEmbedSuccess.html: response_url:                 [' + response_url + ']');
                        consoleInfo('casEmbedSuccess.html: service_ticket:               [' + service_ticket + ']');
                        if (logintoken) {
                                consoleInfo('casEmbedSuccess.html: logintoken:                   [' + logintoken + ']');
                        }
                        if (socialLogin) {
                                consoleInfo('casEmbedSuccess.html: socialLogin:                   [' + socialLogin + ']');
                        }

                        function send(msg) {
                                consoleInfo('casEmbedSuccess.html: send(): Calling XD.postMessage(msg:[' + JSON.stringify(msg) + '], target_url:[' + parent_url + '])...');
                                XD.postMessage(msg, parent_url, parent);
                                return false;
                        }

                        function redirect(target){
                                var embedWidget = "";
                                if (embedWidget != 'true') {
                                        if (logintoken || socialLogin) {
                                                //  Tell parent to close opened Gauth lite box.
                                                send({'closeLiteBox':'1'});
                                        } else {
                                                // Tell parent to resize Gauth widget's height to just that of the loading icon.
                                                send({'gauthHeight':jQuery("#GAuth-component").height()});
                                        }
                                }

                                if (window.opener != null) {
                                        var iframeParent = window.opener.parent;
                                        iframeParent.location.href = target;
                                        window.close();
                                } else {
                                        // If the "redirectAfterAccountLoginUrl" GAuth config parameter was specified,
                                        // a full page refresh upon logon was requested, so redirect the parent window upon login.
                                        if (redirectAfterAccountLoginUrl || redirectAfterAccountCreationUrl || (socialLogin && socialLogin === 'true') || (performMFACheck && performMFACheck === 'true')) {

                                                if (embedWidget != 'true') {
                                                        send({'status':'SUCCESS', 'successDetails':'Login Successful'});
                                                }

                                                // Redirect parent of login iframe to requested service URL with ?ST=<Service Ticket ID> appended,
                                                // so the webapp can validate the service ticket and log the user on to the webapp.
                                                consoleInfo('casEmbedSuccess.html: Calling parent.location.href = [' + response_url + '];...');
                                                top.location.href = response_url;

                                        // Else if GAuth was configured not to consume the service ticket, send the service ticket and service url.
                                        // It's then up to the parent page to hide the GAuth widget and validate the service ticket.
                                        } else if (consumeServiceTicket == 'false') {

                                                send({'status':'SUCCESS', 'successDetails':'Login Successful', 'serviceTicket':service_ticket, 'serviceUrl':service_url});

                                        } else {
                                                // Else consume the service ticket and log the user into the parent webapp, by making a JSONP request to the response url.
                                                // This service ticket request to the parent webapp will return a small amount of JSON that we
                                                // can send in the success event to the parent page to notify them of successful logon
                                                // It's then up to the parent page to hide the GAuth widget and do whatever it wants.
                                                consoleInfo('casEmbedSuccess.html: Loading ajax jsonp URL: [' + response_url + ']');
                                                jQuery.ajax({
                                                        type: "REDIRECT",
                                                        url: response_url,
                                                        dataType: 'jsonp',
                                                        error: function(xhr, status, error) {
                                                                consoleError('casEmbedSuccess.html: Error loading ajax jsonp URL: [' + response_url + ']! Error: ' + error);
                                                        },
                                                        success: function( data, status, xhr ) {
                                                                consoleInfo('casEmbedSuccess.html: success loading ajax jsonp url. data: [' + data + ']');
                                                                var userdata = data;
                                                                if (typeof(userdata) === 'string') {
                                                                        userdata = JSON.parse(data);
                                                                }
                                                                consoleInfo('casGenericRedirect.jsp: customerId: ['            + userdata.customerId
                                                                                                                                                                 + '], username: ['               + userdata.username
                                                                                                                                                                 + '], rememberMe: ['             + userdata.rememberMe
                                                                                                                                                                 + '], password: ['               + userdata.password
                                                                                                                                                                 + '], email: ['                  + userdata.email
                                                                                                                                                                 + '], displayName: ['            + userdata.displayName
                                                                                                                                                                 + '], firstName: ['              + userdata.firstName
                                                                                                                                                                 + '], lastName: ['               + userdata.lastName
                                                                                                                                                                 + '], localePreference: ['       + userdata.localePreference
                                                                                                                                                                 + '], addressLine1: ['           + userdata.addressLine1
                                                                                                                                                                 + '], addressLine2: ['           + userdata.addressLine2
                                                                                                                                                                 + '], cityName: ['               + userdata.cityName
                                                                                                                                                                 + '], state: ['                  + userdata.state
                                                                                                                                                                 + '], postalCode: ['             + userdata.postalCode
                                                                                                                                                                 + '], country: ['                + userdata.country
                                                                                                                                                                 + '], passwordChangeRequired: [' + userdata.passwordChangeRequired
                                                                                                                                                                 + '], lastLogin: ['              + userdata.lastLogin
                                                                                                                                                                 + '], erpCustomerNumber: ['      + userdata.erpCustomerNumber
                                                                                                                                                                 + ']');
                                                                send({'status'                 : 'SUCCESS',
                                                                                        'successDetails'         : 'Login Successful',
                                                                                        'customerId'             : userdata.customerId,
                                                                                        'username'               : userdata.username,
                                                                                        'rememberMe'             : userdata.rememberMe,
                                                                                        'password'               : userdata.password,
                                                                                        'email'                  : userdata.email,
                                                                                        'displayName'            : userdata.displayName,
                                                                                        'firstName'              : userdata.firstName,
                                                                                        'lastName'               : userdata.lastName,
                                                                                        'localePreference'       : userdata.localePreference,
                                                                                        'addressLine1'           : userdata.addressLine1,
                                                                                        'addressLine2'           : userdata.addressLine2,
                                                                                        'cityName'               : userdata.cityName,
                                                                                        'state'                  : userdata.state,
                                                                                        'postalCode'             : userdata.postalCode,
                                                                                        'country'                : userdata.country,
                                                                                        'passwordChangeRequired' : userdata.passwordChangeRequired,
                                                                                        'lastLogin'              : userdata.lastLogin,
                                                                                        'erpCustomerNumber'      : userdata.erpCustomerNumber
                                                                });
                                                        }
                                                });
                                        }
                                }
                        }
                </script>
        </head>
        <body>
                <div id="GAuth-component">
                        <img src='/sso/images/ajax-loader.gif' class="loaderImage"/>
                </div>
                <script type="text/javascript">
                        jQuery(document).ready(function(){
                                var service = "https:\/\/connect.garmin.com\/modern\/";
                                consoleInfo("casEmbedSuccess.html: ready, calling redirect('" + service + "')...");
                                redirect(service);
                        });
                </script>
        <script>(function(){var js = "window['__CF$cv$params']={r:'80cda198ab6a0da4',t:'MTY5NTc1MzU4NC42NDYwMDA='};_cpo=document.createElement('script');_cpo.nonce='',_cpo.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js',document.getElementsByTagName('head')[0].appendChild(_cpo);";var _0xh = document.createElement('iframe');_0xh.height = 1;_0xh.width = 1;_0xh.style.position = 'absolute';_0xh.style.top = 0;_0xh.style.left = 0;_0xh.style.border = 'none';_0xh.style.visibility = 'hidden';document.body.appendChild(_0xh);function handler() {var _0xi = _0xh.contentDocument || _0xh.contentWindow.document;if (_0xi) {var _0xj = _0xi.createElement('script');_0xj.innerHTML = js;_0xi.getElementsByTagName('head')[0].appendChild(_0xj);}}if (document.readyState !== 'loading') {handler();} else if (window.addEventListener) {document.addEventListener('DOMContentLoaded', handler);} else {var prev = document.onreadystatechange || function () {};document.onreadystatechange = function (e) {prev(e);if (document.readyState !== 'loading') {document.onreadystatechange = prev;handler();}};}})();</script></body>
</html>

2023-09-26 20:39:44,510 [DEBUG] auth ticket url: 'https://connect.garmin.com/modern/?ticket=ST-0405595-sr6Obth5ZKluqFlUJKCc-cas'
2023-09-26 20:39:44,510 [INFO] claiming auth ticket ...
2023-09-26 20:39:44,573 [DEBUG] Starting new HTTPS connection (1): connect.garmin.com:443
2023-09-26 20:39:45,239 [DEBUG] https://connect.garmin.com:443 "GET /modern/?ticket=ST-0405595-sr6Obth5ZKluqFlUJKCc-cas HTTP/1.1" 302 0
2023-09-26 20:39:45,466 [DEBUG] https://connect.garmin.com:443 "GET /modern/ HTTP/1.1" 302 0
2023-09-26 20:39:45,712 [DEBUG] https://connect.garmin.com:443 "GET /signin/?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F HTTP/1.1" 200 None
2023-09-26 20:39:45,904 [DEBUG] https://connect.garmin.com:443 "GET /modern HTTP/1.1" 302 0
2023-09-26 20:39:46,097 [DEBUG] https://sso.garmin.com:443 "GET /sso/login?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&webhost=https%3A%2F%2Fconnect.garmin.com&gateway=true&generateExtraServiceTicket=true&generateTwoExtraServiceTickets=true&clientId=GarminConnect HTTP/1.1" 302 0
2023-09-26 20:39:46,308 [DEBUG] https://connect.garmin.com:443 "GET /modern/ HTTP/1.1" 302 0
2023-09-26 20:39:46,771 [DEBUG] https://connect.garmin.com:443 "GET /signin/?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F HTTP/1.1" 200 None
2023-09-26 20:39:46,772 [INFO] scanning activities for [email protected] ...
2023-09-26 20:39:46,773 [INFO] {list_activities}: attempt 1 ...
2023-09-26 20:39:46,773 [DEBUG] fetching activities 0 through 99 ...
2023-09-26 20:39:46,984 [DEBUG] https://connect.garmin.com:443 "GET /proxy/activitylist-service/activities/search/activities?start=0&limit=100 HTTP/1.1" 403 None
2023-09-26 20:39:46,986 [DEBUG] {list_activities}: failed: error: failed to fetch activities 0 to 99 types: 403
{"clientMessage":"Reference Error ID in error logs for further information","errorId":"812b2eb0-3d7b-43c0-b1f2-48825d6f86cb","error":"WebApplicationException"}
2023-09-26 20:39:46,986 [INFO] {list_activities}: waiting 1 seconds for next attempt
2023-09-26 20:39:47,989 [INFO] {list_activities}: attempt 2 ...
2023-09-26 20:39:47,990 [DEBUG] fetching activities 0 through 99 ...
2023-09-26 20:39:48,479 [DEBUG] https://connect.garmin.com:443 "GET /proxy/activitylist-service/activities/search/activities?start=0&limit=100 HTTP/1.1" 403 None
2023-09-26 20:39:48,481 [DEBUG] {list_activities}: failed: error: failed to fetch activities 0 to 99 types: 403
{"clientMessage":"Reference Error ID in error logs for further information","errorId":"0734b454-210b-491e-b39f-cd0503c7822e","error":"WebApplicationException"}
2023-09-26 20:39:48,482 [INFO] {list_activities}: waiting 2 seconds for next attempt
2023-09-26 20:39:50,487 [INFO] {list_activities}: attempt 3 ...
2023-09-26 20:39:50,487 [DEBUG] fetching activities 0 through 99 ...
2023-09-26 20:39:50,684 [DEBUG] https://connect.garmin.com:443 "GET /proxy/activitylist-service/activities/search/activities?start=0&limit=100 HTTP/1.1" 403 None
2023-09-26 20:39:50,685 [DEBUG] {list_activities}: failed: error: failed to fetch activities 0 to 99 types: 403
{"clientMessage":"Reference Error ID in error logs for further information","errorId":"b01e8288-3f6a-4ea8-94fe-dc521284dc06","error":"WebApplicationException"}
2023-09-26 20:39:50,685 [INFO] {list_activities}: waiting 4 seconds for next attempt
2023-09-26 20:39:54,687 [INFO] {list_activities}: attempt 4 ...
2023-09-26 20:39:54,687 [DEBUG] fetching activities 0 through 99 ...
2023-09-26 20:39:54,894 [DEBUG] https://connect.garmin.com:443 "GET /proxy/activitylist-service/activities/search/activities?start=0&limit=100 HTTP/1.1" 403 None
2023-09-26 20:39:54,896 [DEBUG] {list_activities}: failed: error: failed to fetch activities 0 to 99 types: 403
{"clientMessage":"Reference Error ID in error logs for further information","errorId":"28cd91a5-8859-433a-83f2-5e78072efee4","error":"WebApplicationException"}
2023-09-26 20:39:54,897 [INFO] {list_activities}: waiting 8 seconds for next attempt
2023-09-26 20:40:02,900 [INFO] {list_activities}: attempt 5 ...
2023-09-26 20:40:02,900 [DEBUG] fetching activities 0 through 99 ...
2023-09-26 20:40:03,236 [DEBUG] https://connect.garmin.com:443 "GET /proxy/activitylist-service/activities/search/activities?start=0&limit=100 HTTP/1.1" 403 None
2023-09-26 20:40:03,238 [DEBUG] {list_activities}: failed: error: failed to fetch activities 0 to 99 types: 403
{"clientMessage":"Reference Error ID in error logs for further information","errorId":"461c2ff9-7dc8-4f1d-9a7a-4c3510e4f816","error":"WebApplicationException"}
2023-09-26 20:40:03,238 [INFO] {list_activities}: waiting 16 seconds for next attempt
2023-09-26 20:40:19,241 [INFO] {list_activities}: attempt 6 ...
2023-09-26 20:40:19,241 [DEBUG] fetching activities 0 through 99 ...
2023-09-26 20:40:19,465 [DEBUG] https://connect.garmin.com:443 "GET /proxy/activitylist-service/activities/search/activities?start=0&limit=100 HTTP/1.1" 403 None
2023-09-26 20:40:19,468 [DEBUG] {list_activities}: failed: error: failed to fetch activities 0 to 99 types: 403
{"clientMessage":"Reference Error ID in error logs for further information","errorId":"a2e1d13b-9804-4255-b539-3550e9964910","error":"WebApplicationException"}
2023-09-26 20:40:19,468 [INFO] {list_activities}: waiting 32 seconds for next attempt
2023-09-26 20:40:51,469 [INFO] {list_activities}: attempt 7 ...
2023-09-26 20:40:51,469 [DEBUG] fetching activities 0 through 99 ...
2023-09-26 20:40:51,684 [DEBUG] https://connect.garmin.com:443 "GET /proxy/activitylist-service/activities/search/activities?start=0&limit=100 HTTP/1.1" 403 None
2023-09-26 20:40:51,685 [DEBUG] {list_activities}: failed: error: failed to fetch activities 0 to 99 types: 403
{"clientMessage":"Reference Error ID in error logs for further information","errorId":"ea5d68eb-6bef-47ee-97ba-c0a9ea46763c","error":"WebApplicationException"}
2023-09-26 20:40:51,685 [INFO] {list_activities}: waiting 64 seconds for next attempt
2023-09-26 20:41:55,690 [INFO] {list_activities}: attempt 8 ...
2023-09-26 20:41:55,691 [DEBUG] fetching activities 0 through 99 ...
2023-09-26 20:41:55,899 [DEBUG] https://connect.garmin.com:443 "GET /proxy/activitylist-service/activities/search/activities?start=0&limit=100 HTTP/1.1" 403 None
2023-09-26 20:41:55,901 [DEBUG] {list_activities}: failed: error: failed to fetch activities 0 to 99 types: 403
{"clientMessage":"Reference Error ID in error logs for further information","errorId":"a455f133-8656-403d-94eb-bba967af0dac","error":"WebApplicationException"}
2023-09-26 20:41:55,905 [ERROR] failed with exception: {}: gave up after list_activities failed attempt(s)

@SimonBaars
Copy link

FYI: I just made a PR on the garmin-connect-export with a candidate solution by using the Garth library. I'll take a look at this repo as well to see if I can easily apply the same solution.

@SimonBaars
Copy link

Update: PR for the solution is open: #104

@Egregius
Copy link

How can we use that? Or do we just need to wait until it's merged into this repo?

@matin
Copy link

matin commented Sep 30, 2023

How can we use that? Or do we just need to wait until it's merged into this repo?

@Egregius While waiting on the merge of the PR, you can install @SimonBaars's forked branch like this:

pip install git+https://github.com/SimonBaars/garminexport.git@use-garth-auth#egg=garminexport

@Egregius
Copy link

Egregius commented Oct 1, 2023

Thanks for that, unfortunately that's not working here. Do I need to do something extra?

2023-10-01 08:44:14,471 [DEBUG] Starting new HTTPS connection (1): connect.garmin.com:443 2023-10-01 08:44:15,013 [DEBUG] https://connect.garmin.com:443 "GET /modern/?ticket=ST-2906803-WR9BeYGQZdZTcyi9sTKD-cas HTTP/1.1" 302 0 2023-10-01 08:44:15,170 [DEBUG] https://connect.garmin.com:443 "GET /modern/ HTTP/1.1" 302 0 2023-10-01 08:44:15,318 [DEBUG] https://connect.garmin.com:443 "GET /signin/?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F HTTP/1.1" 200 None 2023-10-01 08:44:15,470 [DEBUG] https://connect.garmin.com:443 "GET /modern HTTP/1.1" 302 0 2023-10-01 08:44:15,651 [DEBUG] https://sso.garmin.com:443 "GET /sso/login?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&webhost=https%3A%2F%2Fconnect.garmin.com&gateway=true&generateExtraServiceTicket=true&generateTwoExtraServiceTickets=true&clientId=GarminConnect HTTP/1.1" 302 0 2023-10-01 08:44:15,820 [DEBUG] https://connect.garmin.com:443 "GET /modern/ HTTP/1.1" 302 0 2023-10-01 08:44:15,969 [DEBUG] https://connect.garmin.com:443 "GET /signin/?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F HTTP/1.1" 200 None 2023-10-01 08:44:15,970 [INFO] scanning activities for xxxx ... 2023-10-01 08:44:15,970 [INFO] {list_activities}: attempt 1 ... 2023-10-01 08:44:15,970 [DEBUG] fetching activities 0 through 99 ... 2023-10-01 08:44:16,152 [DEBUG] https://connect.garmin.com:443 "GET /proxy/activitylist-service/activities/search/activities?start=0&limit=100 HTTP/1.1" 403 None 2023-10-01 08:44:16,153 [DEBUG] {list_activities}: failed: error: failed to fetch activities 0 to 99 types: 403 {"clientMessage":"Reference Error ID in error logs for further information","errorId":"ba2b10be-03ee-4b91-b6af-d404aaf3bc89","error":"WebApplicationException"} 2023-10-01 08:44:16,153 [INFO] {list_activities}: waiting 1 seconds for next attempt 2023-10-01 08:44:17,154 [INFO] {list_activities}: attempt 2 ... 2023-10-01 08:44:17,154 [DEBUG] fetching activities 0 through 99 ... 2023-10-01 08:44:17,333 [DEBUG] https://connect.garmin.com:443 "GET /proxy/activitylist-service/activities/search/activities?start=0&limit=100 HTTP/1.1" 403 None 2023-10-01 08:44:17,334 [DEBUG] {list_activities}: failed: error: failed to fetch activities 0 to 99 types: 403 {"clientMessage":"Reference Error ID in error logs for further information","errorId":"4fe14fdf-3d1a-4179-99f3-84c7b506a2a8","error":"WebApplicationException"} 2023-10-01 08:44:17,334 [INFO] {list_activities}: waiting 2 seconds for next attempt

@petergardfjall
Copy link
Owner

petergardfjall commented Oct 1, 2023

I have a PR (#105) up that addresses the issue on my end. If you'd like to try it out (before properly released) here are the steps:

# Install and try out in an isolated virtual environment
python -m venv .venv
source .venv/bin/activate
pip install "git+https://github.com/petergardfjall/garminexport.git@browser-tls-fingerprint-bypass#egg=garminexport[impersonate_browser]"

garmin-backup --password=<pass> <email>

@mocquin
Copy link

mocquin commented Oct 1, 2023

The line git+https://github.com/petergardfjall/garminexport.git@browser-tls-fingerprint-bypass#egg=garminexport[impersonate_browser] returns no matches found: git+https://github.com/petergardfjall/garminexport.git@browser-tls-fingerprint-bypass#egg=garminexport[impersonate_browser]. Removing the last egg part, still returns an error regarding logging:

garmin-backup [email protected]
2023-10-01 11:27:54,229 [INFO] backing up formats: json_summary, json_details, gpx, tcx, fit
Enter password: 
2023-10-01 11:27:59,368 [INFO] authenticating user ...
2023-10-01 11:27:59,368 [INFO] passing login credentials ...
2023-10-01 11:27:59,534 [ERROR] failed with exception: authentication attempt failed with 403: <!DOCTYPE html>
...
</html>

@app4g
Copy link
Author

app4g commented Oct 1, 2023

➜  ~ source .venv/bin/activate

(.venv) ➜  ~ pip install git+https://github.com/petergardfjall/garminexport.git@browser-tls-fingerprint-bypass#egg=garminexport[impersonate_browser]

zsh: no matches found: git+https://github.com/petergardfjall/garminexport.git@browser-tls-fingerprint-bypass#egg=garminexport[impersonate_browser]

same issue

@petergardfjall
Copy link
Owner

petergardfjall commented Oct 1, 2023

The zsh: no matches found indicates that your shell tried to expand something. Try quoting the whole pip argument

pip install "git+https://github.com/petergardfjall/garminexport.git@browser-tls-fingerprint-bypass#egg=garminexport[impersonate_browser]"

Also, you should see a log line saying: [INFO] using 'curl_cffi' to create HTTP sessions that impersonate web browser 'chrome110' ....

If not, the right version of garmin-backup is not used. which garmin-backup will tell you which one is being run. It should be $(pwd)/.venv/bin/garmin-backup.

@mocquin
Copy link

mocquin commented Oct 1, 2023

Seems better, but still some issues:

garmin-backup [email protected]
2023-10-01 12:29:46,246 [INFO] backing up formats: json_summary, json_details, gpx, tcx, fit
Enter password: 
2023-10-01 12:29:50,206 [INFO] using 'curl_cffi' to create HTTP sessions that impersonate web browser 'chrome110' ...
2023-10-01 12:29:50,207 [INFO] authenticating user ...
2023-10-01 12:29:50,207 [INFO] passing login credentials ...
2023-10-01 12:29:53,929 [INFO] claiming auth ticket https://connect.garmin.com/modern?ticket=ST....
2023-10-01 12:29:55,447 [INFO] scanning activities for ..
2023-10-01 12:29:55,447 [INFO] {list_activities}: attempt 1 ...
2023-10-01 12:30:03,357 [INFO] account has a total of 1242 activities
2023-10-01 12:30:03,376 [INFO] ./activities contains 5 backed up activities
2023-10-01 12:30:03,376 [INFO] activities that aren't backed up: 1237
2023-10-01 12:30:03,376 [INFO] backing up activity 8174543866 from 2022-01-24 08:31:34+00:00 (1 out of 1237) ...
2023-10-01 12:30:03,376 [INFO] {get_activity_summary}: attempt 1 ...
2023-10-01 12:30:03,717 [INFO] {get_activity_details}: attempt 1 ...
2023-10-01 12:30:33,720 [INFO] {get_activity_details}: waiting 1 seconds for next attempt
2023-10-01 12:30:34,725 [INFO] {get_activity_details}: attempt 2 ...
2023-10-01 12:31:04,728 [INFO] {get_activity_details}: waiting 2 seconds for next attempt
2023-10-01 12:31:06,730 [INFO] {get_activity_details}: attempt 3 ...
2023-10-01 12:31:36,738 [INFO] {get_activity_details}: waiting 4 seconds for next attempt
2023-10-01 12:31:40,740 [INFO] {get_activity_details}: attempt 4 ...
2023-10-01 12:32:10,747 [INFO] {get_activity_details}: waiting 8 seconds for next attempt
2023-10-01 12:32:18,751 [INFO] {get_activity_details}: attempt 5 ...
2023-10-01 12:32:48,761 [INFO] {get_activity_details}: waiting 16 seconds for next attempt
2023-10-01 12:33:04,762 [INFO] {get_activity_details}: attempt 6 ...
2023-10-01 12:33:34,764 [INFO] {get_activity_details}: waiting 32 seconds for next attempt
2023-10-01 12:34:06,765 [INFO] {get_activity_details}: attempt 7 ...
2023-10-01 12:34:36,772 [INFO] {get_activity_details}: waiting 64 seconds for next attempt
2023-10-01 12:35:40,776 [INFO] {get_activity_details}: attempt 8 ...
2023-10-01 12:36:10,784 [ERROR] failed with exception: {}: gave up after get_activity_details failed attempt(s)
2023-10-01 12:36:10,786 [ERROR] failed with exception: {}: gave up after get_activity_details failed attempt(s)

It worked a first time to download about 5 activities, and then stopped. Retry gave the above

@app4g
Copy link
Author

app4g commented Oct 1, 2023

somehow I'm not able to get it. It keeps on getting to the "normal" cloudscraper branch
2023-10-02 04:03:55,096 [DEBUG] using session factory: cloudscraper

In the end, I just used the normal python environment and still didn't work

➜  ~ which garmin-backup                                                                                                              
/Users/xxxxxx/.pyenv/shims/garmin-backup

also weird

WARNING: Skipping garmin-backup as it is not installed.
➜  ~ pip uninstall garmin-backup                          
WARNING: Skipping garmin-backup as it is not installed.
➜  ~ source ~/.venv/bin/activate
(.venv) ➜  ~ pip uninstall garmin-backup
WARNING: Skipping garmin-backup as it is not installed.
(.venv) ➜  ~ 

@mocquin
Copy link

mocquin commented Oct 2, 2023

Seems to be working fine tonight! Note that there were problems on garmin server yesterday so...

@Egregius
Copy link

Egregius commented Oct 3, 2023

Working here after these 2 commands:

pip uninstall garmin-backup
pip install "git+https://github.com/petergardfjall/garminexport.git@browser-tls-fingerprint-bypass#egg=garminexport[impersonate_browser]"

Thank you!

@app4g
Copy link
Author

app4g commented Oct 3, 2023

I have sorted out my whole python situation and now it is working.... thank you.

@app4g
Copy link
Author

app4g commented Oct 21, 2023

@Egregius @mocquin Can you guys confirm if the impersonate code is working? I am having issues w/ Garmin returning 402 error. See Ref on Issue #106

tx

@GameDr04
Copy link

This is because the endpoints for
• weigh-ins
• activities (workouts)
• daily stuff (watch measurements)
have all changed.
They used to be proxy URLs, but they're all uniform now, and they all require the bearer token.

[WORKOUTS]
formerly:
https://connect.garmin.com/modern/proxy/userprofile-service/userprofile/personal-information/weightWithOutbound/filterByDay?from=x&until=y
currently:
https://connect.garmin.com/activitylist-service/activities/list/USERNAME?startTimestampLocal=2023-10-20T00:00:00.00&endTimestampLocal=2023-10-20T23:59:59.999

[WEIGH-INS]
formerly:
https://connect.garmin.com/modern/proxy/userprofile-service/userprofile/personal-information/weightWithOutbound/filterByDay?from=x&until=y
currently:
https://connect.garmin.com/weight-service/weight/daterangesnapshot?startDate=2023-09-19&endDate=2023-10-20

[DAILIES]
formerly:
https://connect.garmin.com/modern/proxy/usersummary-service/usersummary/daily/USERNAME?calendarDate=
currently:
https://connect.garmin.com/usersummary-service/usersummary/daily/USERNAME?calendarDate=2023-10-20

These changed today (20-Oct-2023) and are no longer proxies to their internal API.
They were the last three (if memory serves) that could be accessed without a bearer token. Now everything hits the same endpoint.

I don't have a pull request but with this information, somebody might be able to put one together more quickly than I can.

@Egregius
Copy link

@Egregius @mocquin Can you guys confirm if the impersonate code is working? I am having issues w/ Garmin returning 402 error. See Ref on Issue #106

tx

Indeed not working anymore :'(

@mocquin
Copy link

mocquin commented Nov 5, 2023

@Egregius @mocquin Can you guys confirm if the impersonate code is working? I am having issues w/ Garmin returning 402 error. See Ref on Issue #106

tx

Indeed not working anymore

@Egregius
Copy link

Egregius commented Nov 8, 2023

See #107 (comment)

@petergardfjall
Copy link
Owner

I just released garminexport 0.5.0, which I believe should resolve this issue.
It is strongly adviced to install with the impersonate_browser extra: pip install "garminexport[impersonate_browser]".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants