{"id":55000460,"date":"2025-02-01T00:00:00","date_gmt":"2025-04-23T16:22:52","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=460"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"eBay_per_VBA_steuern_Zugangsdaten_holen","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/eBay_per_VBA_steuern_Zugangsdaten_holen\/","title":{"rendered":"eBay per VBA steuern: Zugangsdaten holen"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg08.met.vgwort.de\/na\/a29b831ef8234c2ba2a0e1bf3d0505b9\" width=\"1\" height=\"1\" alt=\"\"><b>Im ersten Teil einer Artikelreihe zum Thema Steuerung von eBay mit VBA zeigen wir, wie man einen Entwickler-Account anlegt, eine neue Anwendung bei eBay erstellt, grundlegende Zugriffsdaten holt und die f&uuml;r die Authentifizierung im Kontext eines bestimmten Benutzerkontos notwendigen Informationen holt &#8211; hier speziell das Authentifizierungstoken. Damit schaffen wir die Basis, um per VBA auf die Rest API von eBay zuzugreifen. In weiteren Artikeln beschreiben wir den Zugriff und wie wir verschiedene Operationen wie das Anlegen von Angeboten realisieren k&ouml;nnen.<\/b><\/p>\n<p>Um eBay mit VBA zu steuern, brauchen wir als Erstes ein Konto im <b>ebay developers program<\/b>. Um dorthin zu gelangen, reicht eine Websuche nach den Begriffen <b>ebay developer<\/b>.<\/p>\n<p>F&uuml;r die Registrierung werden die folgenden Informationen ben&ouml;tigt, die wir in ein Formular wie in Bild 1 eintragen: Benutzername, Kennwort, E-Mail-Adresse und Telefonnummer. Nachdem wir diese eingetragen und die Schaltfl&auml;che <b>Join <\/b>bet&auml;tigt haben, landen wir auf der n&auml;chsten Seite im Registrierungsprozess.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_001.png\" alt=\"Registrieren f&uuml;r das Developer-Program von eBay\" width=\"549,6265\" height=\"822,355\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Registrieren f&uuml;r das Developer-Program von eBay<\/span><\/b><\/p>\n<p>Hier erhalten wir den Hinweis, dass eBay uns eine E-Mail zugesendet hat. Diese enth&auml;lt einen Best&auml;tigungslink, mit dem wir den Vorgang fortsetzen k&ouml;nnen.<\/p>\n<p>Nachdem wir diesen bet&auml;tigt haben, landen wir auf der Willkommen-Seite des Entwicklerprogramms und k&ouml;nnen uns dort mit unseren Daten anmelden (siehe Bild 2).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_003.png\" alt=\"Anmelden beim Developer-Program von eBay\" width=\"499,6267\" height=\"468,4927\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Anmelden beim Developer-Program von eBay<\/span><\/b><\/p>\n<p>Die Freude w&auml;hrt in der Regel nur kurz, denn gegebenenfalls bekommen wir hier die Meldung, dass die Registrierung nun &uuml;berpr&uuml;ft wird und in ca. 24 Stunden freigeschaltet wird.<\/p>\n<p>Einen Tag sp&auml;ter k&ouml;nnen wir uns dann ohne Probleme beim eBay-Entwicklerprogramm anmelden.<\/p>\n<h2>Erstellen einer neuen Anwendung<\/h2>\n<p>eBay macht es uns dann erst einmal einfach: Da wir das Entwickler-Konto gerade er&ouml;ffnet haben und folglich noch keine Anwendungen hinzugef&uuml;gt haben, ohne eine Anwendung aber der Developer-Account keinen Sinn macht, landen wir direkt auf der Seite zum Erstellen einer Anwendung.<\/p>\n<p>Dies beginnt mit der Eingabe eines Anwendungstitels, der vor allem eine Bedingung erf&uuml;llen muss: eBay darf nicht im Namen vorkommen (siehe Bild 3).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_004.png\" alt=\"Erstellen einer ersten Anwendung\" width=\"499,6267\" height=\"349,6572\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Erstellen einer ersten Anwendung<\/span><\/b><\/p>\n<p>Wir entscheiden uns f&uuml;r <b>amvBay<\/b> und noch w&auml;hrend wir diesen Namen eingeben, erscheinen bereits verschiedene Links f&uuml;r weitere M&ouml;glichkeiten (siehe Bild 4). Diese sind aufgeteilt in Sandbox und Production. Was bedeutet das?<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_005.png\" alt=\"Noch w&auml;hrend der Eingabe des Namens erscheinen die Optionen zum Erstellen von Keysets.\" width=\"700\" height=\"378,8388\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Noch w&auml;hrend der Eingabe des Namens erscheinen die Optionen zum Erstellen von Keysets.<\/span><\/b><\/p>\n<ul>\n<li>In der <b>Sandbox <\/b>k&ouml;nnen wir testen, ohne dass wir etwas an bestehenden Konten, Angeboten et cetera kaputtmachen.<\/li>\n<li><b>Production <\/b>hei&szlig;t: Hier arbeiten wir mit echten Benutzern und Angeboten. Hier sollten wir keine Fehler mehr produzieren und beispielsweise beim Experimentieren mit der <b>L&ouml;schen<\/b>-Funktion auf Kundendaten losgehen.<\/li>\n<\/ul>\n<p>Beide Settings sind gleich aufgebaut, f&uuml;r beide ben&ouml;tigen wir entsprechenden Daten f&uuml;r den Zugriff. Diese hei&szlig;en in diesem Fall <b>Keysets<\/b>.<\/p>\n<p>Wir k&ouml;nnen hier Keysets erstellen oder weitere Keysets anfragen. Was hat es damit auf sich? Wir klicken also erst einmal auf den Link <b>Create a keyset <\/b>unter Sandbox.<\/p>\n<p>Daraufhin erscheint der Bereich <b>Confirm the Primary Contact<\/b>, wo wir weitere Daten wie Name, E-Mail und Telefonnummer eingeben beziehungsweise best&auml;tigen (siehe Bild 5).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_006.png\" alt=\"Eingabe weiterer Daten\" width=\"499,6267\" height=\"513,902\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Eingabe weiterer Daten<\/span><\/b><\/p>\n<p>Ein Klick auf <b>Continue to Create Keys <\/b>l&auml;sst uns wieder zur aufrufenden Seite zur&uuml;ckkehren, wo wir nun allerdings einige neue Informationen vorfinden (siehe Bild 6).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_007.png\" alt=\"Unser Keyset\" width=\"499,6267\" height=\"578,194\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Unser Keyset<\/span><\/b><\/p>\n<p>Dabei handelt es sich um unser Keyset, mit dem wir nun fortfahren k&ouml;nnen:<\/p>\n<ul>\n<li><b>App ID<\/b><\/li>\n<li><b>Dev ID<\/b><\/li>\n<li><b>Cert ID<\/b><\/li>\n<\/ul>\n<p>Diese Informationen k&ouml;nnen wir nun bereits in einem VBA-Modul sichern, am einfachsten in Konstanten. Das sieht wie folgt aus:<\/p>\n<pre>Const cStrAppID<span style=\"color:blue;\"> As String<\/span> = \"AndrMinh-amvBay-xxx-xxxxxxxxx-3e3a632f\"\r\nConst cStrDevID<span style=\"color:blue;\"> As String<\/span> = \"e7df1909-ee64-xxxxxxxx-32138d2b1899\"\r\nConst cStrCertID<span style=\"color:blue;\"> As String<\/span> = \"SBX-4b5baea0d7a2-xxxx-xxxx-8644-6824\"<\/pre>\n<h2>Token holen<\/h2>\n<p>Damit haben wir allerdings noch nicht alles, was wir ben&ouml;tigen. Das Wichtigste ist das Authentifizierungstoken. Hier ist eine kurze Erkl&auml;rung n&ouml;tig:<\/p>\n<p>Wir erstellen hier eine Anwendung, f&uuml;r die eigentlich zwei Konten erforderlich sind: das Entwicklerkonto, das wir soeben erstellt haben, sowie das eigentliche eBay-Konto.<\/p>\n<p>Um eBay komplett fernsteuern zu k&ouml;nnen, m&uuml;ssen wir uns ein Authentifizierungstoken f&uuml;r unsere Anwendung im Kontext des eigentlichen Benutzers holen.<\/p>\n<p>Damit k&ouml;nnen wir dann die Anwendung im Kontext des jeweiligen Benutzers verwenden.<\/p>\n<p>Wir gehen an dieser Stelle davon aus, dass wir eine Anwendung f&uuml;r den Zugriff auf eBay erstellen, um diese beispielsweise in die Warenwirtschaft eines Kunden zu implementieren, damit dieser seine Produkte automatisiert bei eBay einstellen kann.<\/p>\n<p>Nur wollen wir nun zun&auml;chst nicht im Kontext des echten Benutzers auf eBay zugreifen, sondern erst einmal die Sandbox nutzen. Da die Sandbox praktisch ein eigenes eBay zum Testen ist, k&ouml;nnen wir logischerweise dort auch nicht mit unserem normalen eBay-Konto arbeiten, sondern m&uuml;ssen uns ein neues Konto anlegen.<\/p>\n<p>Dazu klicken wir erst einmal unter unserer <b>App ID <\/b>(<b>Client ID<\/b>) auf den Link <b>Register a new Sandbox user<\/b> (siehe Bild 7).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_008.png\" alt=\"Aufruf der Registrierung eines Sandbox-Benutzers\" width=\"649,627\" height=\"450,0208\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Aufruf der Registrierung eines Sandbox-Benutzers<\/span><\/b><\/p>\n<h2>Neuen Sandbox-Benutzer anlegen<\/h2>\n<p>Das Anlegen des neuen Sandbox-Benutzers f&uuml;hren wir in dem Formular aus Bild 8 durch. Nach dem Registrieren k&ouml;nnen wir uns an der Sandbox anmelden.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_009.png\" alt=\"Eingabe der Daten f&uuml;r einen Sandbox-Benutzer\" width=\"424,6267\" height=\"758,77\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Eingabe der Daten f&uuml;r einen Sandbox-Benutzer<\/span><\/b><\/p>\n<p>Hier finden wir allerdings zun&auml;chst keine Angebote vor.<\/p>\n<h2>Token f&uuml;r diesen Benutzer holen<\/h2>\n<p>Nun wollen wir das Token holen, indem wir uns &uuml;ber unsere eBay-Anwendung mit den Daten unseres soeben erstellen Sandbox-Benutzers bei der Sandbox anmelden.<\/p>\n<p>Dazu klicken wir im vorherigen Dialog auf <b>Sign in to Sandbox<\/b> (siehe Bild 9).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_010.png\" alt=\"Anmeldung an der Sandbox\" width=\"499,6267\" height=\"240,5611\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Anmeldung an der Sandbox<\/span><\/b><\/p>\n<p>Damit erscheint nochmals ein Bereich, in dem wir unsere Adresse und weitere Daten eingeben m&uuml;ssen (siehe Bild 10).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_011.png\" alt=\"Eingabe unserer Adressdaten f&uuml;r die Token-Generierung\" width=\"424,6267\" height=\"775,812\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Eingabe unserer Adressdaten f&uuml;r die Token-Generierung<\/span><\/b><\/p>\n<p>Nun erscheint der Anmeldedialog von der eBay-Sandbox, wo wir uns nun mit den Daten unseres Sandbox-Benutzers anmelden (nicht mit dem Developer-Account!).<\/p>\n<p>Schlie&szlig;lich erhalten wir eine Meldung, die uns als Sandbox-Benutzer dar&uuml;ber aufkl&auml;rt, dass wir der App die Berechtigungen geben, unser Konto f&uuml;r verschiedene Aktionen auf der Sandbox von eBay zu nutzen. Im Anschluss erhielten wir jedoch eine Fehlermeldung (siehe Bild 11).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_016.png\" alt=\"Fehlermeldung beim Versuch, das Token zu holen\" width=\"424,6267\" height=\"470,506\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 11: Fehlermeldung beim Versuch, das Token zu holen<\/span><\/b><\/p>\n<p>Bei unseren Recherchen zu diesem Artikel waren wir in der Folge nicht in der Lage, ein Authentifizierungstoken f&uuml;r die Sandbox zu holen, also haben wir es mit der <b>Production<\/b>-Version probiert.<\/p>\n<p>Hier erschien beim Versuch, ein Keyset zu holen, zun&auml;chst die Meldung aus Bild 12.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_013.png\" alt=\"Das Keyset ist aktuell deaktiviert.\" width=\"424,6267\" height=\"282,6483\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 12: Das Keyset ist aktuell deaktiviert.<\/span><\/b><\/p>\n<p>Daraufhin haben wir uns, um weiterarbeiten zu k&ouml;nnen, f&uuml;r die Beantragung einer Ausnahme beworben (siehe Bild 13). Dazu haben wir unter <b>Event Notification Delivery Method <\/b>die Option <b>Marketplace Account Deletion <\/b>gew&auml;hlt und <b>Exempted from Marketplace Account Deletion <\/b>aktiviert. Nach dem Absenden mit <b>Submit <\/b>wurde dies umgehend akzeptiert.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_014.png\" alt=\"Optionen f&uuml;r eine Ausnahme\" width=\"424,6267\" height=\"196,7783\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 13: Optionen f&uuml;r eine Ausnahme<\/span><\/b><\/p>\n<p>Danach haben wir im oberen Bereich der Webseite den Link <b>Get OAuth Application Token <\/b>vorgefunden (siehe Bild 14).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_015.png\" alt=\"Link zum Holen des Authentifizierungstokens\" width=\"700\" height=\"104,3977\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 14: Link zum Holen des Authentifizierungstokens<\/span><\/b><\/p>\n<p>Danach mussten wir uns erneut authentifizieren, um das Token zu holen. Dazu haben wir diesmal nicht den Sandbox-Benutzer verwendet, den wir zuvor angelegt haben, sondern einen echten eBay-Benutzeraccount.<\/p>\n<p>Nach der Authentifizierung und der Zustimmung, dass unsere eBay-Anwendung <b>amvBay<\/b> im Kontext unseres Benutzers auf eBay zugreifen darf, landen wir wieder auf der Token-Seite. Hier k&ouml;nnen wir nun erneut auf <b>Get OAuth Application Token <\/b>klicken und erhalten endlich das Token (siehe Bild 15), das wir in die Zwischenablage kopieren und in einer weiteren Konstanten in unserem VBA-Projekt speichern:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_017.png\" alt=\"Das ersehnte OAuth Application Token\" width=\"599,6265\" height=\"360,4574\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 15: Das ersehnte OAuth Application Token<\/span><\/b><\/p>\n<pre>Const cStrUserToken<span style=\"color:blue;\"> As String<\/span> = \"v^1.1#i^1#p^1#I^3#r^...\"<\/pre>\n<p>Das Token ist zeitlich begrenzt g&uuml;ltig, in diesem Fall 18 Monate. Du solltest dies, wenn Du eine eBay-Anwendung f&uuml;r einen Kunden programmierst, auf jeden Fall im Blick behalten und gegebenenfalls rechtzeitig f&uuml;r eine Aktualisierung des Tokens &uuml;ber den hier vorgestellten Weg sorgen.<\/p>\n<h2>Anwendungstoken holen<\/h2>\n<p>Das Benutzertoken k&ouml;nnen wir nutzen, um benutzerspezifische Aufrufe der Rest API zu authentifizieren. Es gibt jedoch auch einige Rest API-Befehle, die allgemein verf&uuml;gbar sind und nicht im Kontext eines speziellen Benutzers stehen.<\/p>\n<p>In diesem Fall k&ouml;nnen wir das Benutzertoken nicht verwenden, sondern wir ben&ouml;tigen ein Anwendungstoken. Das holen wir uns auf der gleichen Seite, auf der wir auch die Erstellung des Benutzertokens initiiert haben. Hier klicken wir nun im oberen Bereich auf <b>Get OAuth Application Token <\/b>(siehe Bild 16).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_018.png\" alt=\"Ermitteln des Anwendungstokens\" width=\"649,627\" height=\"289,9341\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 16: Ermitteln des Anwendungstokens<\/span><\/b><\/p>\n<p>Nun &ouml;ffnet sich ein Dialog namens <b>OAuth Application Token<\/b>, dessen Inhalt wir &uuml;ber die Schaltfl&auml;che <b>Copy Token <\/b>in die Zwischenablage kopieren k&ouml;nnen (siehe Bild 17).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_019.png\" alt=\"Kopieren des Anwendungstokens\" width=\"424,6267\" height=\"538,3425\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 17: Kopieren des Anwendungstokens<\/span><\/b><\/p>\n<p>Auch dieses Token wollen wir in einer Konstanten speichern, diesmal unter dem Namen <b>cStrAppToken<\/b>.<\/p>\n<p>Das ist etwas komplizierter, denn eine Zeile zur Definition einer Konstanten kann nur 1.023 Zeichen aufnehmen, das Token hat allerdings eine L&auml;nge von &uuml;ber 1.900 Zeichen.<\/p>\n<p>Am einfachsten kopierst Du es zun&auml;chst in eine Textdatei, schneidest dort die ersten 950 Zeichen aus und f&uuml;gst sie der ersten Zeile der folgenden Anweisung hinzu. Den Rest tr&auml;gst Du dann in die zweite Zeile ein, die Du mit dem Unterstrich und dem Und-Zeichen verbindest:<\/p>\n<pre>Const cStrAppToken<span style=\"color:blue;\"> As String<\/span> = \"v^1.1#i^1#r^0#p^1#...\" _\r\n     & \"EAGuOQLyjgblGU8zkk+nJIBIAGIx8Vg4P9TJre...==\"<\/pre>\n<h2>Nachteil: G&uuml;ltigkeitsdauer dieser Daten<\/h2>\n<p>Ein gro&szlig;er Nachteil, wenn wir die Daten so &uuml;ber die Benutzeroberfl&auml;che holen, ist die geringe Haltbarkeit:<\/p>\n<ul>\n<li>Das Anwendungstoken ist f&uuml;r ca. zwei Stunden g&uuml;ltig.<\/li>\n<li>Das Benutzertoken ist nur ca. eine Stunde g&uuml;ltig.<\/li>\n<li>Ein Refresh-Token ist 18 Monate g&uuml;ltig und kann zum Erneuern des Benutzertokens verwendet werden.<\/li>\n<\/ul>\n<p>Was bedeutet das f&uuml;r uns? Nach aktuellem Stand m&uuml;ssten wir alle zwei Stunden oder, wenn wir beispielsweise einmal am Tag auf eBay-Daten zugreifen wollen, immer neue Daten holen.<\/p>\n<p>Da es auf Dauer viel Aufwand ist, sich immer in der Benutzeroberfl&auml;che der Entwicklerplattform von eBay einzuloggen, wollen wir diese Vorg&auml;nge m&ouml;glichst per VBA steuern.<\/p>\n<h2>Wann brauche ich welches Token?<\/h2>\n<p>Die beiden Token haben unterschiedliche Ziele:<\/p>\n<ul>\n<li>Mit dem Anwendungstoken (<b>App Token<\/b>) autentifizieren wir uns f&uuml;r allgemeine Funktionen, die auch dem normalen Benutzer ohne Anmeldung zur Verf&uuml;gung stehen.<\/li>\n<li>Mit dem Benutzertoken (<b>User Access Token<\/b>) k&ouml;nnen wir auf pers&ouml;nliche oder gesch&uuml;tzte Daten im Namen eines eBay-Benutzers zugreifen. Deshalb ist dieses Token schwieriger zu erhalten.<\/li>\n<\/ul>\n<h2>Anwendungsbereiche f&uuml;r das Anwendungstoken<\/h2>\n<p>Mit dem Anwendungstoken k&ouml;nnen wir die folgenden Bereiche abfragen:<\/p>\n<ul>\n<li><b>Browse API<\/b>: Artikelsuche, Kategorien, Angebote ansehen<\/li>\n<li><b>Buy Marketing API<\/b>: Werbung, Deals, Sonderaktionen<\/li>\n<li><b>Buy Recommendation API<\/b>: Vorschl&auml;ge f&uuml;r &auml;hnliche Artikel<\/li>\n<li><b>Taxonomy API<\/b>: Kategorien, Aspekte, Filter<\/li>\n<\/ul>\n<h2>Anwendungsbereiche f&uuml;r das Benutzertoken<\/h2>\n<p>Das Benutzertoken ben&ouml;tigen wir f&uuml;r die folgenden Aktionen:<\/p>\n<ul>\n<li><b>Artikel kaufen <\/b>(Checkout): Nur mit Login des K&auml;ufers<\/li>\n<li><b>Bestellungen abrufen<\/b>: Du bekommst nur die Bestellungen eines eingeloggten Verk&auml;ufers<\/li>\n<li><b>Listings verwalten <\/b>(verkaufen): Inserate erstellen, beenden, &auml;ndern<\/li>\n<li><b>Nachrichten abrufen oder senden<\/b>: zum Beispiel K&auml;uferkommunikation<\/li>\n<li><b>Transaktionen, Bewertungen, Analytics<\/b>: Zugriff auf verkaufsbezogene Metriken<\/li>\n<li><b>Benutzerdaten abrufen <\/b>(Name, Adresse, etc.): Zum Beispiel f&uuml;r Rechnungen, Versand<\/li>\n<\/ul>\n<h2>Anwendungstoken per VBA holen<\/h2>\n<p>Das Anwendungstoken k&ouml;nnen wir uns ohne irgendeine Interaktion mit der Benutzeroberfl&auml;che von eBay per VBA holen. Dazu ben&ouml;tigen wir die folgenden drei Informationen:<\/p>\n<ul>\n<li><b>AppID<\/b>: Wie oben in der Konstanten <b>cStrAppID <\/b>gespeichert, wird f&uuml;r den Parameter <b>strClientID <\/b>&uuml;bergeben.<\/li>\n<li><b>CertID<\/b>: Wie oben in der Konstanten <b>cStrCertID <\/b>gespeichert, wird f&uuml;r den Parameter <b>strClientSecret <\/b>&uuml;bergeben.<\/li>\n<li>Api-Scope: Eine neue Konstante namens <b>cStrAPIScope<\/b>, die wir wie folgt anlegen:<\/li>\n<\/ul>\n<pre><span style=\"color:blue;\">Public <\/span>Const cStrAPIScope<span style=\"color:blue;\"> As String<\/span> = \"https:\/\/api.ebay.com\/oauth\/api_scope\"<\/pre>\n<p>Diese drei Informationen &uuml;bergeben wir an die Funktion <b>GetEbayAppToken<\/b> aus Listing 1. Diese deklariert einige Variablen, f&uuml;r die wir auch noch Verweise zum VBA-Projekt hinzuf&uuml;gen m&uuml;ssen. Au&szlig;erdem verwenden wir hier Funktionen, die wir direkt per VBA-Modul zum VBA-Projekt hinzuf&uuml;gen k&ouml;nnen. Zusammengefasst ben&ouml;tigen wir:<\/p>\n<pre><span style=\"color:blue;\">Function <\/span>GetEbayAppToken(strClientId<span style=\"color:blue;\"> As String<\/span>, strClientSecret<span style=\"color:blue;\"> As String<\/span>, strScope<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objXMLHTTP<span style=\"color:blue;\"> As <\/span>MSXML2.XMLHTTP60\r\n     <span style=\"color:blue;\">Dim <\/span>strTokenURL<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strAuthHeader<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strPostData<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strResponse<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objJSON<span style=\"color:blue;\"> As Object<\/span>\r\n     strAuthHeader = \"Basic \" & Base64Encode(strClientId & \":\" & strClientSecret)\r\n     strTokenURL = \"https:\/\/api.ebay.com\/identity\/v1\/oauth2\/token\"\r\n     strPostData = \"grant_type=client_credentials&scope=\" & strScope\r\n     <span style=\"color:blue;\">Set<\/span> objXMLHTTP = CreateObject(\"MSXML2.XMLHTTP\")\r\n     <span style=\"color:blue;\">With<\/span> objXMLHTTP\r\n         .Open \"POST\", strTokenURL, <span style=\"color:blue;\">False<\/span>\r\n         .setRequestHeader \"Content-Type\", \"application\/x-www-form-urlencoded\"\r\n         .setRequestHeader \"Authorization\", strAuthHeader\r\n         .send strPostData\r\n         strResponse = .responseText\r\n     End <span style=\"color:blue;\">With<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> objJSON = ParseJson(strResponse)\r\n     <span style=\"color:blue;\">Debug.Print<\/span> GetJSONDOM(strResponse, <span style=\"color:blue;\">True<\/span>)\r\n     GetEbayAppToken = objJSON.Item(\"access_token\")\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Funktion, um das Anwendungstoken zu holen<\/span><\/b><\/p>\n<ul>\n<li>Verweis auf die Bibliothek <b>Microsoft XML, v6.0<\/b><\/li>\n<li>Verweis auf die Bibliothek <b>Microsoft Scripting Runtime<\/b><\/li>\n<li>Modul <b>mdlJSON<\/b><\/li>\n<li>Modul <b>mdlJSONDOM<\/b><\/li>\n<\/ul>\n<p>Die Funktion stellt die Zeichenfolge f&uuml;r die Authentifizierung aus dem Wort <b>Basic <\/b>und dem Base64-verschl&uuml;sselten Wert aus <b>ClientID <\/b>und <b>ClientSecret <\/b>zusammen &#8211; getrennt durch einen Doppelpunkt.<\/p>\n<p>Damit f&uuml;gen wir in der Variablen <b>strTokenURL <\/b>die URL f&uuml;r den Abruf des Tokens zusammen.<\/p>\n<p>Nun erstellen wir in <b>objXMLHTTP <\/b>ein <b>MSXML2.XMLHTTP<\/b>-Objekt, dem wir mit der <b>Open<\/b>-Methode die Methode <b>POST<\/b>, die <b>URL <\/b>und den Wert <b>False <\/b>f&uuml;r den Parameter <b>varAsync <\/b>&uuml;bergeben.<\/p>\n<p>Wir stellen den Autorisierung-Header auf unseren Wert aus <b>strAuthheader <\/b>ein. Dann senden wir die Zeichenkette aus <b>strPostData <\/b>an die Rest-API und &uuml;bernehmen die Antwort aus der Eigenschaft <b>responseText <\/b>in die Variable <b>strPostData<\/b>.<\/p>\n<p>Die Antwort verarbeiten wir mit der Funktion <b>ParseJson<\/b> aus dem Modul <b>mdlJSON<\/b>. Diese erstellt aus dem zur&uuml;ckgelieferten JSON-Dokument ein Objektmodell, bestehend aus <b>Dictionary<\/b>&#8211; und <b>Collections<\/b>-Objekten.<\/p>\n<p>Damit wir sehen, welche Elemente hier zur&uuml;ckgeliefert werden, rufen wir die Methode <b>GetJSONDOM <\/b>f&uuml;r die Antwort auf und erhalten ein Ergebnis wie in Bild 19.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_022.png\" alt=\"Per VBA geholtes Anwendungstoken\" width=\"599,6265\" height=\"179,2606\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 18: Per VBA geholtes Anwendungstoken<\/span><\/b><\/p>\n<p>Die dort jeweils am Zeilenbeginn angegebenen Ausdr&uuml;cke wie <b>objJSON.Item(&#8220;access_token&#8221;) <\/b>k&ouml;nnen wir nutzen, um die in diesen Elementen enthaltenen Daten zu extrahieren. In diesem Fall greifen wir so auf das Element <b>access_token <\/b>zu und geben dieses als Funktionswert zur&uuml;ck.<\/p>\n<p>Die Funktion rufen wir wie folgt aus:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>Test_GetEbayAppToken()\r\n     <span style=\"color:blue;\">Debug.Print<\/span> GetEbayAppToken(cStrAppID, _\r\n         cStrCertID, cStrAPIScope)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Was k&ouml;nnen wir jetzt mit dem Ergebnis dieser Funktion anstellen? Aktuell noch nichts. Allerdings wollen wir im Artikel <b>eBay per VBA steuern: Rest-API-Zugriff <\/b>(<b>www.vbentwickler.de\/461<\/b>) auf die Angebote bei eBay zugreifen und dazu ben&ouml;tigen wir das hier ermittelte Anwendungstoken.<\/p>\n<h2>Benutzertoken per VBA holen<\/h2>\n<p>Um das Benutzertoken per VBA zu holen, ben&ouml;tigen wir noch eine weitere Einstellung in der Benutzeroberfl&auml;che der Entwickler-Plattform von eBay. Das erledigen wir auf der gleichen Seite, auf der wir auch die Tokens geholt haben.<\/p>\n<p>Hier scrollen wir etwas weiter nach unten zum Bereich <b>Get a Token from eBay via Your Application<\/b>. Unter <b>Your eBay Sign-in-Settings <\/b>klicken wir auf <b>Add eBay Redirect URL <\/b>(siehe Bild 18).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_020.png\" alt=\"Redirect URL festlegen\" width=\"599,6265\" height=\"203,318\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 19: Redirect URL festlegen<\/span><\/b><\/p>\n<p>Wir landen in einem erweiterten Formular. Hier findest Du oben unter <b>RuName<\/b> eine Zeichenkette, die wir ben&ouml;tigen und in die Zwischenablage kopieren (siehe Bild 20). Von dort f&uuml;gen wir sie einer neuen Konstanten namens <b>cStrRuName <\/b>hinzu:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_021.png\" alt=\"RuName ist das, was wir suchen\" width=\"599,6265\" height=\"593,0735\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 20: RuName ist das, was wir suchen<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Const cStrRuName<span style=\"color:blue;\"> As String<\/span> = _\r\n     \"Andr__Minhorst-AndrMinh-amvBay-fxndr\"<\/pre>\n<p>Diese setzen wir in eine URL wie die folgende ein:<\/p>\n<pre>https:\/\/auth.ebay.com\/oauth2\/authorize?client_id=DEINE_CLIENT_ID&response_type=code&redirect_uri=DEIN_REGISTRIERTER_RUNAME_WERT&scope=https:\/\/api.ebay.com\/oauth\/api_scope<\/pre>\n<p>Danach k&uuml;mmern wir uns in dieser Reihenfolge um die folgenden Schritte:<\/p>\n<ul>\n<li>Anmelden im Kontext eines Benutzers, um einen Autorisierungscode zu erhalten<\/li>\n<li>Mit diesem holen wir dann per VBA das <b>User Access Token<\/b>, also den Benutzertoken und das <b>Refresh Token<\/b>.<\/li>\n<\/ul>\n<p>Der erste Schritt ist etwas hakelig, aber wenn wir das Refresh Token haben, k&ouml;nnen wir f&uuml;r eine Weile im Kontext des Benutzers auf eBay zugreifen, ohne uns erneut &uuml;ber die Benutzeroberfl&auml;che anmelden zu m&uuml;ssen.<\/p>\n<p>Dazu k&ouml;nnen wir ein paar Prozeduren nutzen, mit denen wir automatisch zu der Seite gelangen, auf der wir uns im Kontext eines Benutzers anmelden k&ouml;nnen. Hier bekommen wir allerdings erst einmal den Autorisierungscode.<\/p>\n<p>Die erste hei&szlig;t <b>StartLogin<\/b>. Sie stellt mit einer Hilfsfunktion die URL zusammen, unter der wir den Schl&uuml;ssel erhalten (siehe Listing 2).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>StarteLogin()\r\n     <span style=\"color:blue;\">Dim <\/span>strLoginURL<span style=\"color:blue;\"> As String<\/span>\r\n     strLoginURL = GetEbayLoginUrl(cStrAppID, cStrRuName, \"https:\/\/api.ebay.com\/oauth\/api_scope\")\r\n     FollowHyperlink strLoginURL\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Funktion, um den Authentifizierungscode zu holen<\/span><\/b><\/p>\n<p>Die Hilfsfunktion hei&szlig;t <b>GetEbayLoginUrl<\/b> und sieht wie in Listing 3 aus. Sie f&uuml;gt unsere Parameter zu der ben&ouml;tigten URL zusammen.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>GetEbayLoginUrl(strClientId<span style=\"color:blue;\"> As String<\/span>, strRuName<span style=\"color:blue;\"> As String<\/span>, strScopes<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>url<span style=\"color:blue;\"> As String<\/span>\r\n     ''alles au&szlig;er Punkte wird urlencodiert\r\n     url = \"https:\/\/auth.ebay.com\/oauth2\/authorize?\" & _\r\n           \"client_id=\" & URLEncodeEBay(strClientId) & _\r\n           \"&response_type=code\" & _\r\n           \"&redirect_uri=\" & URLEncodeEBay(strRuName) & _\r\n           \"&scope=\" & URLEncodeEBay(strScopes)\r\n     GetEbayLoginUrl = url\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Funktion zum Zusammenstellen der URL<\/span><\/b><\/p>\n<p>Die Prozedur <b>StarteLogin<\/b> ruft dann mit <b>FollowHyperlink <\/b>den Browser auf und &uuml;bergibt die zusammengestellte URL.<\/p>\n<p>Hier finden wir nun einen Anmeldedialog f&uuml;r eBay vor (siehe Bild 21).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_023.png\" alt=\"Anmelden im Kontext eines Benutzers\" width=\"599,6265\" height=\"303,5224\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 21: Anmelden im Kontext eines Benutzers<\/span><\/b><\/p>\n<p>Nachdem wir uns hier angemeldet haben, k&ouml;nnen wir oben in der URL den Code ermitteln (siehe Bild 22).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_024.png\" alt=\"Auslesen des Codes\" width=\"649,627\" height=\"350,2627\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 22: Auslesen des Codes<\/span><\/b><\/p>\n<p>Dieser sieht beispielsweise wie folgt aus:<\/p>\n<pre>https:\/\/auth2.ebay.com\/oauth2\/ThirdPartyAuthSucessFailure?isAuthSuccessful=true&code=v%5E1.1%23i%5E1%23r%5E1%23I%5E3%23f%5E0%23p%5E3%23t%5EUl41Xzk6RTJBQjYyNEY4M0I5QTcyMTczQjlDMDA2MzFDMUU2MzFfMF8xI0VeMjYw&expires_in=299<\/pre>\n<p>Der entscheidende Teil ist der Text hinter <b>code=<\/b> und vor <b>&#038;expires_in=299<\/b>. Hier sehen wir die typischen Elemente einer URL-codierten Zeichenkette. Diese speichern wir kodiert ab und dekodieren sie sp&auml;ter, wenn wir sie ben&ouml;tigen. Die notwendige Konstante definieren wir nun wie folgt:<\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Const cStrCode<span style=\"color:blue;\"> As String<\/span> = \"v%5E1.1%23i%5E1%23r%5E1%23I%5E3%23f%5E0%23p%5E3%23t%5EUl41Xzk6RTJBQjYyNEY4M0I5QTcyMTczQjlDMDA2MzFDMUU2MzFfMF8xI0VeMjYw\"<\/pre>\n<p>In der Antwort wird durch den Wert <b>299 <\/b>f&uuml;r den Parameter <b>expires_in <\/b>deutlich: Wir haben nur knapp f&uuml;nf Minuten, um diesen Code zu nutzen, also kannst Du die Konstante zwar bereits anlegen.<\/p>\n<p>Aber nutzen k&ouml;nnen wir diese erst in den nachfolgend beschriebenen Prozeduren zum Ermitteln von Benutzertoken und Refreshtoken. Gegebenenfalls musst Du den Code also erneut holen.<\/p>\n<h2>Scopes anpassen oder erweitern<\/h2>\n<p>Wir haben oben nur den Scope <b>https:\/\/api.ebay.com\/oauth\/api_scope <\/b>angegeben. Es kann sp&auml;ter sein, dass Du mehr Berechtigungen f&uuml;r weitere API-Funktionen ben&ouml;tigst.<\/p>\n<p>Die notwendigen URLs findest Du, wenn Du auf der Seite mit den <b>Application Keys <\/b>unten auf <b>OAuth Scopes <\/b>klickst. Dies &ouml;ffnet ein Popup mit den Scopes wie in Bild 23.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_026.png\" alt=\"Scopes der eBay-API\" width=\"499,6267\" height=\"827,186\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 23: Scopes der eBay-API<\/span><\/b><\/p>\n<p>Die URLs in der Spalte <b>Scopes <\/b>kannst Du f&uuml;r den Parameter <b>Scope <\/b>in der Funktion <b>GetEbayLoginUrl <\/b>anh&auml;ngen.<\/p>\n<p>Wenn Du mehrere Scopes verwendest, musst Du diese durch ein als <b>%20 <\/b>kodiertes Leerzeichen voneinander trennen.<\/p>\n<p>Wenn Du neue Scopes hinzuf&uuml;gen musst, weil die aktuellen Scopes f&uuml;r einen bestimmten API-Aufruf nicht ausreichen, musst Du den oben vorgestellten Vorgang wiederholen, also:<\/p>\n<ul>\n<li>Scopes in der Funktion <b>StarteLogin <\/b>anpassen<\/li>\n<li>Funktion <b>StarteLogin <\/b>aufrufen<\/li>\n<li>Authcode aus der URL im Browser auslesen und in <b>cstrCode <\/b>speichern<\/li>\n<li>Damit dann, wie in den folgenden Schritten beschrieben, Benutzertoken und Refreshtoken holen.<\/li>\n<\/ul>\n<h2>Prozedur zum Holen von Benutzertoken und Refreshtoken<\/h2>\n<p>Damit geht es in die Zielgerade. Wir haben alle Zutaten zusammen, um das Benutzertoken zu holen, mit dem wir im Kontext eines Benutzers auf die Daten von eBay zugreifen k&ouml;nnen.<\/p>\n<p>Dieser ist zeitlich allerdings auch stark limitiert (auf 7.200 Sekunden, also zwei Stunden), sodass wir diesen gelegentlich erneuern m&uuml;ssen. Aber kein Problem: Daf&uuml;r erhalten wir mit der nachfolgend beschriebenen Funktion auch gleich ein Refreshtoken, mit dem wir das Benutzertoken aktualisieren k&ouml;nnen &#8211; ohne nochmals die vorherige Prozedur &uuml;ber den Webbrowser zu durchlaufen. Das Refreshtoken h&auml;lt 47.304.000 Sekunden, also eineinhalb Jahre.<\/p>\n<p>Schauen wir uns die Funktion <b>GetEbayUserToken<\/b> aus Listing 4 an. Sie erwartet als Parameter die ClientID, das Client Secret, den Authcode und die RedirectURI. Au&szlig;erdem hat sie einen R&uuml;ckgabeparameter, der die Antwort von eBay zur&uuml;ckliefert.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>GetEbayUserToken(strClientID<span style=\"color:blue;\"> As String<\/span>, strClientSecret<span style=\"color:blue;\"> As String<\/span>, strAuthCode<span style=\"color:blue;\"> As String<\/span>, _\r\n         strRedirectURI<span style=\"color:blue;\"> As String<\/span>, strResponse<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strTokenURL<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strPostData<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strCredentials<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objHttp<span style=\"color:blue;\"> As <\/span>MSXML2.XMLHTTP60\r\n     \r\n     strTokenURL = \"https:\/\/api.ebay.com\/identity\/v1\/oauth2\/token\"\r\n     \r\n     strCredentials = Base64Encode(strClientID & \":\" & strClientSecret)\r\n     strPostData = \"grant_type=authorization_code\" & _\r\n                   \"&code=\" & strAuthCode & _\r\n                   \"&redirect_uri=\" & URLDecode(strRedirectURI)\r\n                   \r\n     <span style=\"color:blue;\">Set<\/span> objHttp = <span style=\"color:blue;\">New<\/span> MSXML2.XMLHTTP60\r\n     <span style=\"color:blue;\">With<\/span> objHttp\r\n         .Open \"POST\", strTokenURL, <span style=\"color:blue;\">False<\/span>\r\n         .setRequestHeader \"Content-Type\", \"application\/x-www-form-urlencoded\"\r\n         .setRequestHeader \"Authorization\", \"Basic \" & strCredentials\r\n         .send strPostData\r\n         \r\n         <span style=\"color:blue;\">If <\/span>.status = 200<span style=\"color:blue;\"> Then<\/span>\r\n             strResponse = .responseText\r\n             GetEbayUserToken = <span style=\"color:blue;\">True<\/span>\r\n             <span style=\"color:blue;\">Debug.Print<\/span> \"Token erhalten: \" & strResponse\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             <span style=\"color:blue;\">Debug.Print<\/span> \"Fehler: \" & .status & \" - \" & .responseText\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Funktion zum Holen des Benutzer- und Refresh-Tokens<\/span><\/b><\/p>\n<p>Damit klar wird, welche Informationen hier gefragt sind, schauen wir uns ein Beispiel f&uuml;r den Aufruf an. Die folgende Prozedur deklariert die Variable <b>strResponse <\/b>f&uuml;r den R&uuml;ckgabewert, die Variable <b>objJSON<\/b> zum Auswerten des zur&uuml;ckgelieferten JSON-Dokuments sowie zwei Variablen f&uuml;r das Benutzertoken und das Refreshtoken.<\/p>\n<p>Damit rufen wir die Funktion <b>GetEbayUserToken <\/b>auf und &uuml;bergeben die Werte aus den Konstanten <b>cStrAppID<\/b>, <b>cStrCertID<\/b>, <b>cStrCode <\/b>und <b>cStrRuName<\/b>.<\/p>\n<p>Hier hat eBay &uuml;ber die Jahre ein wenig Inkonsistenz geschaffen, da die notwendigen Parameter anders hei&szlig;en als die, die wir aus der Benutzeroberfl&auml;che entnehmen k&ouml;nnen &#8211; die AppID entspricht beispielsweise der Client ID, die CertID dem Client Secret und RuName ist die Bezeichnung in der Benutzeroberfl&auml;che f&uuml;r die RedirectURI (ist aber gar keine URI).<\/p>\n<p>Wir behalten aber als Konstantennamen die Bezeichnungen aus der Benutzeroberfl&auml;che bei und verwenden in der Funktion <b>GetEbayUserToken<\/b> die Parameter, wie sie an dieser Stelle benannt werden.<\/p>\n<p>Die Prozedur zum Aufruf &uuml;bergibt also alle notwendigen Daten und erh&auml;lt eine Response im JSON-Format zur&uuml;ck. Diese wandeln wir mit <b>ParseJSON <\/b>in ein Objektmodell aus <b>Dictionary<\/b>&#8211; und <b>Collection<\/b>-Elementen um.<\/p>\n<p>Wie wir auf dieses Objektmodell zugreifen k&ouml;nnen, zeigt uns wieder der Aufruf von <b>GetJSONDOM <\/b>&#8211; dies gibt alle Ausdr&uuml;cke f&uuml;r den Zugriff aus sowie die enthaltenen Werte.<\/p>\n<p>Wir verwenden die am Ende verwendeten Ausdr&uuml;cke f&uuml;r <b>access_token <\/b>und <b>refresh_token <\/b>und weisen deren Inhalte den Variablen <b>strUserToken <\/b>und <b>strRefreshToken <\/b>zu, die wir anschlie&szlig;end in den Benutzerbereich f&uuml;r VBA-Einstellungen in der Registry speichern:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>Test_GetEbayUserToken()\r\n     <span style=\"color:blue;\">Dim <\/span>strResponse<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objJSON<span style=\"color:blue;\"> As Object<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strUserToken<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strRefreshToken<span style=\"color:blue;\"> As String<\/span>\r\n     If GetEbayUserToken(cStrAppID, cStrCertID, cstrCode, _\r\n             cStrRuName, strResponse) = <span style=\"color:blue;\">True<\/span> Then\r\n         <span style=\"color:blue;\">Set<\/span> objJSON = ParseJson(strResponse)\r\n         <span style=\"color:blue;\">Debug.Print<\/span> GetJSONDOM(strResponse, <span style=\"color:blue;\">True<\/span>)\r\n         strUserToken = objJSON.Item(\"access_token\")\r\n         SaveAppSetting \"Usertoken\", strUserToken\r\n         strRefreshToken = objJSON.Item(\"refresh_token\")\r\n         SaveAppSetting \"Refreshtoken\", strRefreshToken\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die beiden Aufrufe der Funktion <b>SaveAppSetting <\/b>tragen die notwendigen Informationen in der Registry ein. Die Funktion haben wir in diesem Artikel beschrieben: <b>Anwendungsdaten in der Registry <\/b>(<b>www.vbentwickler.de\/411<\/b>).<\/p>\n<p>Die Funktion <b>GetEbayUserToken <\/b>nimmt die Parameterwerte entgegen und deklariert gleich einige Variablen. In <b>strTokenURL <\/b>speichert sie die URL, &uuml;ber die wir das Token abfragen.<\/p>\n<p>In <b>strCredentials <\/b>stellen wir eine Base64-kodierte Zeichenfolge aus <b>strClientID<\/b>, einem Doppelpunkt und <b>strClientSecret <\/b>ab. In <b>strPostData <\/b>stellen wir die zu &uuml;bergebenden Daten zusammen. Sie enthalten die Information, dass wir den Autorisierungscode &uuml;bergeben, den wir ebenfalls angeben, und die RedirectURI, die wir an dieser Stelle gleich dekodieren.<\/p>\n<p>Dann folgt der bekannte Ablauf f&uuml;r den Zugriff auf die Rest-API von eBay, wo wir die Informationen &uuml;bergeben und schlie&szlig;lich die <b>send<\/b>-Methode aufrufen. Wir erhalten einen Status zur&uuml;ck, der im Erfolgsfall <b>200 <\/b>lautet. Dann lesen wir aus der Eigenschaft <b>responseText <\/b>die Antwort aus und speichern diese in der Variablen <b>strResponse<\/b>.<\/p>\n<p>Au&szlig;erdem stellen wir den R&uuml;ckgabewert der Funktion auf <b>True <\/b>ein. Bei allen anderen R&uuml;ckgabewerten geben wir den Status und die Antwort im Direktbereich aus.<\/p>\n<p>Grunds&auml;tzlich k&ouml;nnten wir an dieser Stelle auch die &uuml;brigen Daten in die Registry schreiben. Das erledigen wir mit den folgenden Anweisungen:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>RegistryFuellen()\r\n     SaveAppSetting \"AppID\", cStrAppID\r\n     SaveAppSetting \"DevID\", cStrDevID\r\n     SaveAppSetting \"CertID\", cStrCertID\r\n     SaveAppSetting \"RuName\", cStrRuName\r\n     SaveAppSetting \"AuthCode\", cstrCode\r\n     SaveAppSetting \"AppToken\", cStrAppToken\r\n     SaveAppSetting \"APIScope\", cStrAPIScope\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Damit k&ouml;nnen wir die Konstanten nun auskommentieren.<\/p>\n<p>Die Token und die &uuml;brigen Daten befinden sich nun wie in Bild 24 zu sehen in der Registry.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_01\/pic_460_025.png\" alt=\"Token in der Registry\" width=\"649,627\" height=\"257,3838\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 24: Token in der Registry<\/span><\/b><\/p>\n<p>Nun wird das VBA-Projekt allerdings nicht mehr sauber kompiliert. Zum Beispiel die zum Schreiben der Daten in die Registry kann nun nicht mehr auf die Konstanten zugreifen. Diese war jedoch ohnehin nur f&uuml;r den Einmalgebraucht vorgesehen, also k&ouml;nnen wir diese auskommentieren.<\/p>\n<p>An den &uuml;brigen Stellen ersetzen wir die Konstanten durch Aufrufe der Funktion <b>GetAppSetting<\/b>. Den Aufruf der Funktion <b>GetEbayAppToken <\/b>passen wir beispielsweise wie folgt an:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>Test_GetEbayAppToken()\r\n     <span style=\"color:blue;\">Debug.Print<\/span> GetEbayAppToken(GetAppSetting(\"AppID\"), _\r\n         GetAppSetting(\"CertID\"), cStrAPIScope)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Testen des Benutzertokens<\/h2>\n<p>Wir k&ouml;nnen den Artikel nicht beschlie&szlig;en, ohne zumindest einen kurzen Test des Benutzertokens durchzuf&uuml;hren. <\/p>\n<p>Dazu nutzen wir den Abruf der <b>ReturnPolicy<\/b>, also der R&uuml;ckgabebedingungen des Benutzers, in dessen Kontext wir uns anmelden. Das erledigen wir in der Funktion <b>ReturnPolicyEinlesen <\/b>aus Listing 5.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>GetReturnPolicy(strResponse<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strAccessToken<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strURL<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objHttp<span style=\"color:blue;\"> As <\/span>MSXML2.XMLHTTP60\r\n     \r\n     strAccessToken = mdlRegistry.GetAppSetting(\"UserToken\")\r\n     \r\n     strURL = \"https:\/\/api.ebay.com\/sell\/account\/v1\/return_policy\"\r\n     <span style=\"color:blue;\">Set<\/span> objHttp = <span style=\"color:blue;\">New<\/span> MSXML2.XMLHTTP60\r\n     <span style=\"color:blue;\">With<\/span> objHttp\r\n         .Open \"GET\", strURL, <span style=\"color:blue;\">False<\/span>\r\n         .setRequestHeader \"Authorization\", \"Bearer \" & strAccessToken\r\n         .setRequestHeader \"Content-Type\", \"application\/json\"\r\n         .setRequestHeader \"Accept\", \"application\/json\"\r\n         .send\r\n         <span style=\"color:blue;\">If <\/span>.status = 200<span style=\"color:blue;\"> Then<\/span>\r\n             GetReturnPolicy = <span style=\"color:blue;\">True<\/span>\r\n             strResponse = .responseText\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             GetReturnPolicy = <span style=\"color:blue;\">False<\/span>\r\n             strResponse = .responseText\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Funktion zum Einlesen der ReturnPolicy<\/span><\/b><\/p>\n<p>Diese hat nur den Parameter <b>strResponse<\/b>, mit dem das Ergebnis im JSON-Format zur&uuml;ckgegeben werden soll.<\/p>\n<p>Die einzige Information, die wir hier ben&ouml;tigen, ist das Benutzertoken.<\/p>\n<p>Dieses haben wir in den vorherigen Schritten in der Registry gespeichert und holen es mit der Funktion <b>GetAppSetting<\/b>. Die URL f&uuml;r den API-Zugriff schreiben wir in die Variable <b>strURL<\/b>. Damit &ouml;ffnen wir den Zugriff, stellen den Header f&uuml;r die Authentifizierung diesmal auf die Zeichenkette <b>Bearer <\/b>plus <b>Benutzertoken <\/b>ein und senden die Anfrage ab.<\/p>\n<p>Wir erhalten im Erfolgsfall wieder den Wert <b>200 <\/b>f&uuml;r die Eigenschaft <b>status <\/b>zur&uuml;ck, sonst einen anderen Wert.<\/p>\n<p> Davon abh&auml;ngig stellen wir den R&uuml;ckgabewert ein und tragen das Ergebnis aus der Eigenschaft <b>responseText <\/b>in den Parameter <b>strResponse <\/b>ein.<\/p>\n<h2>Aufruf der Funktion GetReturnPolicy<\/h2>\n<p>Den Aufruf gestalten wir wie in der folgenden Prozedur:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>Test_GetReturnPolicy()\r\n     <span style=\"color:blue;\">Dim <\/span>objJSON<span style=\"color:blue;\"> As Object<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strResponse<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">If <\/span>GetReturnPolicy(strResponse) = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> objJSON = ParseJson(strResponse)\r\n         <span style=\"color:blue;\">Debug.Print<\/span> GetJSONDOM(strResponse, <span style=\"color:blue;\">True<\/span>)\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> objJSON = ParseJson(strResponse)\r\n         <span style=\"color:blue;\">Debug.Print<\/span> GetJSONDOM(strResponse, <span style=\"color:blue;\">True<\/span>)\r\n         If objJSON.Item(\"errors\").Item(1).Item(\"message\") _\r\n                 = \"Invalid access token\" Then\r\n             <span style=\"color:blue;\">Call<\/span> RefreshUserToken\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Diese liefert nun f&uuml;r den einfachen Scope, den wir verwenden (<b>https:\/\/api.ebay.com\/oauth\/api_scope<\/b>) nun vermutlich diese Fehlermeldung:<\/p>\n<pre>Insufficient permissions to fulfill the request.<\/pre>\n<p>Wir m&uuml;ssen also den Scope erweitern. Dazu gehen wir wie oben beschreiben vor, nur etwas anders, weil wir die Konstanten nun in die Registry ausgelagert haben. Die Startfunktion sieht nun so aus:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>StarteLogin()\r\n     <span style=\"color:blue;\">Dim <\/span>strLoginURL<span style=\"color:blue;\"> As String<\/span>\r\n     strLoginURL = GetEbayLoginUrl(GetAppSetting(\"AppID\"), _\r\n         GetAppSetting(\"RuName\"), GetAppSetting(\"APIScope\"))\r\n     FollowHyperlink strLoginURL\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Wir m&uuml;ssen also den API-Scope erweitern und in die Registry eintragen, zum Beispiel:<\/p>\n<pre>SaveAppSetting \"APIScope\", \"https:\/\/api.ebay.com\/oauth\/api_scope%20https:\/\/api.ebay.com\/oauth\/api_scope\/sell.account\"<\/pre>\n<p>Dann rufen wir <b>StarteLogin<\/b> auf und kopieren aus der nach der Authentitifizierung in der URL-Leiste erscheinenden Zeichenkette den <b>AuthCode <\/b>heraus und f&uuml;gen diesen ebenfalls in die Registry ein:<\/p>\n<pre>SaveAppSetting \"AuthCode\", \"v%5E1.1%23i%5E1%23p%5E3...jYw\"<\/pre>\n<p>Damit k&ouml;nnen wir dann erneut die Prozedur <b>Test_GetEbayUserToken <\/b>aufrufen, welche das neue Usertoken und Refreshtoken wieder in der Registry ablegt.<\/p>\n<p>Rufen wir die Funktion <b>GetReturnPolicy <\/b>erneut auf. Diesmal erhalten wir keine Fehlermeldung mehr wegen fehlender Berechtigungen, sondern nur den Hinweis darauf, dass noch eine <b>MarketplaceId <\/b>&uuml;bergeben werden muss. Grunds&auml;tzlich haben wir aber so die Funktionsf&auml;higkeit des Benutzertokens nachgewiesen.<\/p>\n<p>Wenn bei verschiedenen weiteren Zugriffen Probleme mit nicht ausreichendem Scope auftauchen, kann man einfach <\/p>\n<h2>Holen eines neuen Benutzertokens<\/h2>\n<p>Wie weiter oben beschrieben, ist die G&uuml;ltigkeitsdauer des Benutzertokens auf zwei Stunden begrenzt. Allerdings haben wir ein Refreshtoken, das eineinhalb Jahre g&uuml;ltig ist und mit dem wir das Usertoken jederzeit aktualisieren k&ouml;nnen.<\/p>\n<p>Dazu verwenden wir die Funktion aus Listing 6.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>RefreshUserToken()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strClientID<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strClientSecret<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strRefreshToken<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strRedirectURI<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strTokenURL<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strPostData<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strCredentials<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objJSON<span style=\"color:blue;\"> As Object<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objHttp<span style=\"color:blue;\"> As <\/span>MSXML2.XMLHTTP60\r\n     strClientID = GetAppSetting(\"AppID\")\r\n     strClientSecret = GetAppSetting(\"CertID\")\r\n     strRefreshToken = GetAppSetting(\"RefreshToken\")\r\n     strRedirectURI = GetAppSetting(\"RuName\")\r\n     strTokenURL = \"https:\/\/api.ebay.com\/identity\/v1\/oauth2\/token\"\r\n     strCredentials = Base64Encode(strClientID & \":\" & strClientSecret)\r\n     strPostData = \"grant_type=refresh_token\" & _\r\n                   \"&refresh_token=\" & strRefreshToken & _\r\n                   \"&scope=https:\/\/api.ebay.com\/oauth\/api_scope\"\r\n     <span style=\"color:blue;\">Set<\/span> objHttp = <span style=\"color:blue;\">New<\/span> MSXML2.XMLHTTP60\r\n     <span style=\"color:blue;\">With<\/span> objHttp\r\n         .Open \"POST\", strTokenURL, <span style=\"color:blue;\">False<\/span>\r\n         .setRequestHeader \"Content-Type\", \"application\/x-www-form-urlencoded\"\r\n         .setRequestHeader \"Authorization\", \"Basic \" & strCredentials\r\n         .send strPostData\r\n         <span style=\"color:blue;\">If <\/span>.status = 200<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">Set<\/span> objJSON = ParseJson(.responseText)\r\n             <span style=\"color:blue;\">Debug.Print<\/span> GetJSONDOM(.responseText, <span style=\"color:blue;\">True<\/span>)\r\n             SaveAppSetting \"Usertoken\", objJSON.Item(\"access_token\")\r\n             RefreshUserToken = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             <span style=\"color:blue;\">Set<\/span> objJSON = ParseJson(.responseText)\r\n             <span style=\"color:blue;\">Debug.Print<\/span> GetJSONDOM(.responseText, <span style=\"color:blue;\">True<\/span>)\r\n             RefreshUserToken = <span style=\"color:blue;\">False<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Funktion zum Aktualisieren des Usertokens<\/span><\/b><\/p>\n<p>In dieser Funktion fragen wir diesmal alle Parameter, die wir in die Registry &uuml;bertragen haben, direkt ab. Dadurch ben&ouml;tigen wir keine Parameter mehr &#8211; auch nicht den f&uuml;r die Response, da wir in diesem Fall die Auswertung direkt intern machen. Das bedeutet, dass wir hier das Objekt <b>objJSON <\/b>direkt in der Funktion erstellen und mit der JSON-Antwort f&uuml;llen und hier auch direkt die notwendigen Informationen extrahieren &#8211; n&auml;mlich das Usertoken. Dieses schreiben wir auch direkt mit <b>SaveAppsetting <\/b>in die Registry.<\/p>\n<p>Wir geben lediglich noch den Wert <b>True <\/b>oder <b>False <\/b>zur&uuml;ck.<\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Damit haben wir alle Daten, die wir von eBay f&uuml;r den Zugriff auf die Rest API ben&ouml;tigen. Wir haben einen Account im eBay-Developerprogramm angelegt, eine neue Anwendung erstellt, in deren Rahmen wir auf die eBay-API zugreifen k&ouml;nnen, ein Keyset sowie Token f&uuml;r verschiedene Zugriffsarten geholt. Schlie&szlig;lich haben wir gezeigt, wie wir diese Token per VBA holen k&ouml;nnen und das Refreshtoken nutzen k&ouml;nnen, um das Usertoken regelm&auml;&szlig;ig zu aktualisieren.<\/p>\n<p>Im n&auml;chsten Artikel namens <b>eBay per VBA steuern: Rest-API-Zugriff <\/b>(<b>www.vbentwickler.de\/461<\/b>) schauen wir uns an, wie wir damit auf die Rest API zugreifen k&ouml;nnen, um nach Angeboten auf eBay zu suchen. In weiteren Artikeln geht es dann darum, zum Beispiel eigene Angebote online zu stellen.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Im ersten Teil einer Artikelreihe zum Thema Steuerung von eBay mit VBA zeigen wir, wie man einen Entwickler-Account anlegt, eine neue Anwendung bei eBay erstellt, grundlegende Zugriffsdaten holt und die f&uuml;r die Authentifizierung im Kontext eines bestimmten Benutzerkontos notwendigen Informationen holt &#8211; hier speziell das Authentifizierungstoken. Damit schaffen wir die Basis, um per VBA auf die Rest API von eBay zuzugreifen. In weiteren Artikeln beschreiben wir den Zugriff und wie wir verschiedene Operationen wie das Anlegen von Angeboten realisieren k&ouml;nnen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[66012025,662025,44000029,44000035,44000012],"tags":[],"yst_prominent_words":[],"class_list":["post-55000460","post","type-post","status-publish","format-standard","hentry","category-66012025","category-662025","category-Access_programmieren","category-COMDLLs_programmieren","category-Interaktiv"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000460","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/comments?post=55000460"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000460\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000460"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000460"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000460"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000460"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}