abrander / garmin-connect Goto Github PK
View Code? Open in Web Editor NEWGolang client for the (unoffical reverse engineered) Garmin Connect API
License: MIT License
Golang client for the (unoffical reverse engineered) Garmin Connect API
License: MIT License
Hi, @abrander
Could you please check if your client is working properly with Garmin API ?
I'm having a connection problem (bodycomposition uses this client) , looks like Garmin changed something:
davidkroell/bodycomposition#14
petergardfjall/garminexport#84
Best Regards
Robert
Is it possible to implement an option to do the tcx/gpx-import ( https://connect.garmin.com/modern/import-data )?
Hi, @abrander
I've build some CLI with your library, and I sometimes get the error forbidden
using the exact same credentials.
Do you know why this is the case? Does a workaround exists?
Some thoughts in this issue: davidkroell/bodycomposition#6
Regards,
David
Hi,
I used a fix version of garmin-connect in the bodycompostion project. I compiled with bodycomposition v2.1.0 and v2.2.0-rc1.
Unfortunately, when using the fix version (v0.0.0-20210602212614-9f867d3d6af9), I get the message:
Error uploading file to Garmin Connect: EOF
When using the old version (v0.0.0-20210202215341-7a00bf55428a), I get the message:
Error uploading file to Garmin Connect: Garmin SSO returned 403 Forbidden
I am not the Author of this project, but I use this project to integrate with the Xiaomi scale. I tried to contact the Author by email and by reporting a issue: davidkroell/bodycomposition#13
Unfortunately, He is probably very busy, so I'm looking for help, because I don't know what the problem is :(
Best Regards,
Robert
Hey โ๐ผ,
I'm trying to authenticate the client via:
./connect authenticate
unfortunately I get the error:
social profile not found in HTML
Is there something I need to do?
Greetings,
Thomas
I have been trying to resolve this, but I'm rather stuck. I'm getting a HTTP 403 error from the authentication request. In the response I see the error code 1020. It almost looks as if it's coming from Cloudflare. Cloudflare seems to suggest that this is a violation of a Firewall rule .
The debug log shows:
Password: 2021/05/16 19:28:21.447975 Client.go:410: Getting CSRF token at https://sso.garmin.com/sso/signin?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&gauthHost=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&generateExtraServiceTicket=true&generateTwoExtraServiceTickets=true
2021/05/16 19:28:21.981128 Client.go:430: Got CSRF token: '5E3F22F52C4BEDDFAC2FAF4E500766B54713DD177A419946361DF2F8A4B37074F65D5D290C1F7057BF61317D7DFF1ADE2040'
2021/05/16 19:28:21.981166 Client.go:432: Trying credentials at https://sso.garmin.com/sso/signin?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&gauthHost=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&generateExtraServiceTicket=true&generateTwoExtraServiceTickets=true
2021/05/16 19:28:22 Garmin SSO returned "403 Forbidden"
and the dump
REQUEST
GET /sso/signin?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&gauthHost=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&generateExtraServiceTicket=true&generateTwoExtraServiceTickets=true HTTP/1.1
Host: sso.garmin.com
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
RESPONSE
HTTP/2.0 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, adrum
Access-Control-Allow-Methods: GET,POST,OPTIONS
Access-Control-Allow-Origin: https://www.garmin.com
Cf-Cache-Status: DYNAMIC
Cf-Ray: 6506aa53aca0dc23-LHR
Cf-Request-Id: 0a1808c8460000dc230b186000000001
Content-Language: en
Content-Type: text/html;charset=UTF-8
Date: Sun, 16 May 2021 18:28:21 GMT
Expect-Ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
Set-Cookie: org.springframework.web.servlet.i18n.CookieLocaleResolver.LOCALE=en; Path=/
Set-Cookie: SESSION=9da1fbed-45ac-4df1-9e49-4f869d9af148; Path=/sso/; Secure; HttpOnly
Set-Cookie: __VCAP_ID__=2d568ade-5435-4be9-72a2-db0e; Path=/; HttpOnly; Secure
Set-Cookie: __cflb=02DiuHkH2SZrbLnjiuXCdJ6du8rSDtVcPFKYygt4GQ5NC; SameSite=Lax; path=/; expires=Mon, 17-May-21 17:28:21 GMT; HttpOnly
Vary: Accept-Encoding
X-Robots-Tag: noindex
X-Vcap-Request-Id: 9b5c31b6-1485-4d94-6141-585de3e17e31
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<script charset='UTF-8' type="70240a049a4b92d4c043f1f8-text/javascript">
window['adrum-start-time'] = new Date().getTime();
(function(config){
config.appKey = 'AD-AAB-AAM-PWF';
config.adrumExtUrlHttp = 'http://cdn.appdynamics.com';
config.adrumExtUrlHttps = 'https://cdn.appdynamics.com';
config.beaconUrlHttp = 'http://col.eum-appdynamics.com';
config.beaconUrlHttps = 'https://col.eum-appdynamics.com';
config.xd = {enable : false};
})(window['adrum-config'] || (window['adrum-config'] = {}));
</script>
<script src="//cdn.appdynamics.com/adrum/adrum-latest.js" type="70240a049a4b92d4c043f1f8-text/javascript"></script>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width" />
<meta http-equiv="X-UA-Compatible" content="IE=edge;" />
<title>GARMIN Authentication Application</title>
<link href="/sso/css/GAuth.css?20210406" rel="stylesheet" type="text/css" media="all" />
<link rel="stylesheet" href=""/>
<script type="70240a049a4b92d4c043f1f8-text/javascript" src="/sso/js/jquery/3.1.1/jquery.min.js?20210319"></script>
<script type="70240a049a4b92d4c043f1f8-text/javascript">jQuery.noConflict();</script>
<script type="70240a049a4b92d4c043f1f8-text/javascript" src="/sso/js/jquery-validate/1.16.0/jquery.validate.min.js?20210319"></script>
<script type="70240a049a4b92d4c043f1f8-text/javascript" src="/sso/js/jsUtils.js?20210406"></script>
<script type="70240a049a4b92d4c043f1f8-text/javascript" src="/sso/js/json2.js"></script>
<script type="70240a049a4b92d4c043f1f8-text/javascript" src="/sso/js/consoleUtils.js?20210319"></script>
<script type="70240a049a4b92d4c043f1f8-text/javascript" src="/sso/js/postmessage.js?20210319"></script>
<script type="70240a049a4b92d4c043f1f8-text/javascript" src="/sso/js/popupWindow.js"></script>
<script type="70240a049a4b92d4c043f1f8-text/javascript" src="/sso/js/base.js?20210406"></script>
<script type="70240a049a4b92d4c043f1f8-text/javascript" src="/sso/js/gigyaUtils.js?20210319"></script>
<script type="70240a049a4b92d4c043f1f8-text/javascript" src="/sso/js/login.js?20210319"></script>
<script type="70240a049a4b92d4c043f1f8-text/javascript">
var parent_url = "";
var status = "";
var result = "";
var clientId = '';
var embedWidget = false;
var isUsernameDefined = (false == true) || (false == true);
// Gigya callback to SocialSignInController for brand new social network users redirects to this page
// to popup Create or Link Social Account page, but has a possibly mangled source parameter
// where "?" is set as "<QM>", so translate it back to "?" here.
parent_url = parent_url.replace('<QM>', '?');
var parent_scheme = parent_url.substring(0, parent_url.indexOf("://"));
var parent_hostname = parent_url.substring(parent_scheme.length + 3, parent_url.length);
if (parent_hostname.indexOf("/") != -1) {
parent_hostname = parent_hostname.substring(0, parent_hostname.indexOf("/"));
}
var parentHost = parent_scheme + "://" + parent_hostname;
var createAccountConfigURL = '\/createNewAccount?service%3Dhttps%253A%252F%252Fconnect.garmin.com%252Fmodern%252F%26gauthHost%3Dhttps%253A%252F%252Fconnect.garmin.com%252Fmodern%252F%26generateExtraServiceTicket%3Dtrue%26generateTwoExtraServiceTickets%3Dtrue';
var socialConfigURL = 'https://sso.garmin.com/sso/socialSignIn?service%3Dhttps%3A%2F%2Fconnect.garmin.com%2Fmodern%2F%26gauthHost%3Dhttps%3A%2F%2Fconnect.garmin.com%2Fmodern%2F%26generateExtraServiceTicket%3Dtrue%26generateTwoExtraServiceTickets%3Dtrue';
var gigyaURL = "https://cdns.gigya.com/js/gigya.js?apiKey=2_R3ZGY8Bqlwwk3_63knoD9wA_m-Y19mAgW61bF_s5k9gymYnMEAtMrJiF5MjF-U7B";
if (createAccountConfigURL.indexOf('%253A%252F%252F') != -1) {
createAccountConfigURL = decodeURIComponent(createAccountConfigURL);
}
consoleInfo('signin.html embedWidget: false, createAccountConfigURL: \/createNewAccount?service%3Dhttps%253A%252F%252Fconnect.garmin.com%252Fmodern%252F%26gauthHost%3Dhttps%253A%252F%252Fconnect.garmin.com%252Fmodern%252F%26generateExtraServiceTicket%3Dtrue%26generateTwoExtraServiceTickets%3Dtrue, socialEnabled: true, gigyaSupported: true, socialConfigURL(): https://sso.garmin.com/sso/socialSignIn?service%3Dhttps%3A%2F%2Fconnect.garmin.com%2Fmodern%2F%26gauthHost%3Dhttps%3A%2F%2Fconnect.garmin.com%2Fmodern%2F%26generateExtraServiceTicket%3Dtrue%26generateTwoExtraServiceTickets%3Dtrue');
if (socialConfigURL.indexOf('%3A%2F%2F') != -1) {
socialConfigURL = decodeURIComponent(socialConfigURL);
}
if( status != null && status != ''){
send({'status':status});
}
jQuery(document).ready( function(){
consoleInfo("signin.html: setting field validation rules...");
jQuery("#username").rules("add",{
required: true,
messages: {
required: "Email is required."
}});
jQuery("#password").rules("add", {
required: true,
messages: {
required: "Password is required."
}
});
consoleInfo("signin.html: done setting field validation rules...");
});
XD.receiveMessage(function(m){
consoleInfo("signin.html: " + m.data + " received on " + window.location.host);
if (m && m.data) {
var md = m.data;
if (typeof(md) === 'string') {
md = JSON.parse(m.data);
}
if (md.setUsername) {
consoleInfo("signin.html: Setting username \"" + md.username + "\"...");
jQuery("#signInWithDiffLink").click(); // Ensure the normal login form is shown.
jQuery("#username").val(md.username);
jQuery("#password").focus();
}
}
}, parentHost);
</script>
</head>
<body>
<!-- begin GAuth component -->
<div id="GAuth-component">
<!-- begin login component-->
<div id="login-component" class="blueForm-basic">
<input type="hidden" id="queryString" value="service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&gauthHost=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&generateExtraServiceTicket=true&generateTwoExtraServiceTickets=true" />
<input type="hidden" id="contextPath" value="/sso" />
<!-- begin login form -->
<div id="login-state-default">
<h2>Sign In</h2>
<form method="post" id="login-form">
<div class="form-alert">
<div id="username-error" style="display:none;"></div>
<div id="password-error" style="display:none;"></div>
</div>
<div class="textfield">
<label for="username">Email</label>
<!-- If the lockToEmailAddress parameter is specified then we want to mark the field as readonly,
preload the email address, and disable the other input so that null isn't sent to the server. We'll
also style the field to have a darker grey background and disable the mouse pointer
-->
<!-- If the lockToEmailAddress parameter is NOT specified then keep the existing functionality and disable the readonly input field
-->
<input class="login_email" name="username" id="username" value="" type="email" spellcheck="false" autocorrect="off" autocapitalize="off"/>
</div>
<div class="textfield">
<label for="password">Password</label>
<a id="loginforgotpassword" class="login-forgot-password" style="cursor:pointer">(Forgot?)</a>
<input type="password" name="password" id="password" spellcheck="false" autocorrect="off" autocapitalize="off" />
<strong id="capslock-warning" class="information" title="Caps lock is on." style="display: none;">Caps lock is on.</strong>
</div>
<input type="hidden" name="embed" value="false"/>
<input type="hidden" name="_csrf" value="5E3F22F52C4BEDDFAC2FAF4E500766B54713DD177A419946361DF2F8A4B37074F65D5D290C1F7057BF61317D7DFF1ADE2040" />
<button type="submit" id="login-btn-signin" class="btn1" accesskey="l">Sign In</button>
<!-- The existence of the "rememberme" parameter at all will remember the user! -->
</form>
</div>
<!-- end login form -->
<!-- begin Create Account message -->
<div id="login-create-account">
</div>
<!-- end Create Account message -->
<!-- begin Social Sign In component -->
<div id="SSI-component">
</div>
<!-- end Social Sign In component -->
<div class="clearfix"></div> <!-- Ensure that GAuth-component div's height is computed correctly. -->
</div>
<!-- end login component-->
</div>
<!-- end GAuth component -->
<script type="70240a049a4b92d4c043f1f8-text/javascript">
jQuery(document).ready(function(){
resizePageOnLoad(jQuery("#GAuth-component").height());
if(isUsernameDefined == true){
// If the user's login just failed, redisplay the email/username specified, and focus them in the password field.
jQuery("#password").focus();
} else if(false == true && result != "PASSWORD_RESET_RESULT"){
// Otherwise focus them in the username field of the login dialog.
jQuery("#username").focus();
}
// Scroll to top of iframe to fix problem where Firefox 3.0-3.6 browsers initially show top of iframe cutoff.
location.href="#";
if(!embedWidget){
jQuery('.createAccountLink').click(function(){
send({'openLiteBox':'createAccountLink', 'popupUrl': createAccountConfigURL, 'popupTitle':'Create An Account', 'clientId':clientId});
});
}
});
</script>
<script src="https://ajax.cloudflare.com/cdn-cgi/scripts/7d0fa10a/cloudflare-static/rocket-loader.min.js" data-cf-settings="70240a049a4b92d4c043f1f8-|49" defer=""></script></body>
</html>
REQUEST
POST /sso/signin?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&gauthHost=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&generateExtraServiceTicket=true&generateTwoExtraServiceTickets=true HTTP/1.1
Host: sso.garmin.com
User-Agent: Go-http-client/1.1
Content-Length: 192
Content-Type: application/x-www-form-urlencoded
Origin: https://sso.garmin.com
Accept-Encoding: gzip
_csrf=5E3F22F52C4BEDDFAC2FAF4E500766B54713DD177A419946361DF2F8A4B37074F65D5D290C1F7057BF61317D7DFF1ADE2040&embed=false&password=<removed>&username=robertwilliams1985%40gmail.com
RESPONSE
HTTP/2.0 403 Forbidden
Content-Length: 16
Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Cf-Ray: 6506aa556f23dc23-LHR
Cf-Request-Id: 0a1808c9660000dc234aa43000000001
Content-Type: text/plain; charset=UTF-8
Date: Sun, 16 May 2021 18:28:21 GMT
Expect-Ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Expires: Thu, 01 Jan 1970 00:00:01 GMT
Server: cloudflare
Vary: Accept-Encoding
X-Frame-Options: SAMEORIGIN
error code: 1020
It's weird, because I have had the client working not that long ago.
I've looked at another library, written in python which I can authenticate fine with: https://github.com/cyberjunky/python-garminconnect. I can see some subtle differences, but nothing obvious as to why this library would no longer work for me.
Hello,
Do you support the 2FA option in garmin to log ?
thanks
By uploading a tcx-file (that worked that way in the past) with the following command:
./connect -s $AUTHFILE activities import data/newrun.tcx
I get now the following error:
invalid character 'w' looking for beginning of value
Uploading the same file(s) via webui (https://connect.garmin.com/modern/import-data) to ensure theres no corruption in the format works
Hey the readme has:
go get github.com/aidun/garmin-connect/connect
instead of
go get github.com/abrander/garmin-connect/connect
in the installation instructions
Again there is a problem with authorization, maybe the solution is a new method of authorization? (OAuth):
petergardfjall/garminexport#104
The problem is already reported in 2 threads using bodycomposition (based on the garmin-connect library):
RobertWojtowicz/export2garmin#31
davidkroell/bodycomposition#19
BR,
Robert
Hi,
When installing on latest Go version 1.17.6
the following error occurs:
go get github.com/abrander/garmin-connect/connect
go get: github.com/abrander/garmin-connect/[email protected] requires
github.com/abrander/[email protected]: reading github.com/abrander/garmin-connect/go.mod at revision v0.0.0: unknown revision v0.0.0
Looks like it is related to changes to Go after 1.15, as both 1.16 and 1.17 seem to be having trouble installing the package.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.