Skip to content

Commit 0029bd7

Browse files
committed
Fix LibreLinkUp API for October 2025 changes
Abbott updated the LibreLinkUp API in October 2025 with new requirements: - New mandatory Account-Id header (SHA-256 hash of user.id) - Updated version requirement to 4.16.0 - Product changed from llu.ios to llu.android Without these changes, all LibreLinkUp connections fail with 403 Forbidden. Changes: - Add crypto require for SHA-256 hashing - Update Defaults.Version from 4.7.0 to 4.16.0 - Update Defaults.Product from llu.ios to llu.android - Add Account-Id header to sessionFromAuth() - Add Account-Id header to dataFromSesssion() - Store userId in session for header generation Fixes authorization errors when connecting to LibreView API. Tested with US region LibreLinkUp accounts.
1 parent 1e63c53 commit 0029bd7

1 file changed

Lines changed: 11 additions & 5 deletions

File tree

lib/sources/librelinkup.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
var qs = require('qs');
33
var url = require('url');
4+
var crypto = require('crypto');
45

56
const _LluApiEndpoints = {
67
AE: "api-ae.libreview.io",
@@ -20,8 +21,8 @@ var Defaults = {
2021
Connections: '/llu/connections',
2122
Graph: '/llu/connections/',
2223
mime: 'application/json',
23-
Version: '4.7.0',
24-
Product: 'llu.ios',
24+
Version: '4.16.0',
25+
Product: 'llu.android',
2526

2627
};
2728
var software = require('../../package.json');
@@ -74,8 +75,11 @@ function linkUpSource (opts, axios) {
7475
return elem.patientId == opts.linkUpPatientId;
7576
}
7677
var token = auth.data.authTicket.token;
78+
var userId = auth.data.user.id;
79+
var accountId = crypto.createHash('sha256').update(userId).digest('hex');
7780
var headers = {
78-
'Authorization': [ 'Bearer', token ].join(' ')
81+
'Authorization': [ 'Bearer', token ].join(' '),
82+
'Account-Id': accountId
7983
};
8084
return http.get(Defaults.Connections, { headers }).then((resp) => {
8185
console.log("CONNECTIONS RESPONSE FROM LIBRELINKUP", resp.status, resp.headers, resp.data);
@@ -94,6 +98,7 @@ function linkUpSource (opts, axios) {
9498
}
9599
var result = connections[0];
96100
result.authTicket = auth.data.authTicket;
101+
result.userId = auth.data.user.id;
97102
console.log("LIBRE SESSION FROM AUTH", result);
98103
return result;
99104

@@ -109,8 +114,10 @@ function linkUpSource (opts, axios) {
109114
var lastUpdatedAt = last_glucose_at.toISOString( );
110115
var graph_url = [Defaults.Graph, session.patientId, '/graph'].join('');
111116
var token = session.authTicket.token;
117+
var accountId = crypto.createHash('sha256').update(session.userId).digest('hex');
112118
var headers = {
113-
'Authorization': `Bearer ${token}`
119+
'Authorization': `Bearer ${token}`,
120+
'Account-Id': accountId
114121
};
115122
return http.get(graph_url, { headers }).then((resp) => {
116123
console.log("RECEIVED LIBRE GRAPH DATA", resp.status, resp.headers, resp.data);
@@ -121,7 +128,6 @@ function linkUpSource (opts, axios) {
121128
var { status, data, ticket } = payload;
122129
var batch = data;
123130
// TODO: TRANSFORM
124-
var last_updated = last_known.entries;
125131
function is_newer (elem) {
126132
if (!last_known) { return true; };
127133
return last_known.entries < new Date(elem.dateString);

0 commit comments

Comments
 (0)