Connecting visual studio code with cloud platform

A few weeks ago I decided to try to connect my visual studio code plugin with my cloud platform trial.

That required to implement oauth2 authentication, which I never coded before. It’s actually pretty simple, you need to get an authorisation token (full source here):

import ClientOAuth2 from "client-oauth2" import opn from "open" const oa = new ClientOAuth2({ authorizationUri: `${uaaUrl}/oauth/authorize`, accessTokenUri: `${uaaUrl}/oauth/token`, redirectUri, // a local webserver you set up in node clientId, clientSecret }) // open the login page in a browser opn(oa.code.getUri()) // wait until the local webserver is called const url = (await callbackRequest).url const token = await oa.code.getToken(url)

Also that requires a service key containing the connection details required.

This will open a tab in your browser to ask you to authorise the application (or authorise it straight away if you’re logged in already)

Once you have a token you just add it to your requests and you’re authenticated:

await got(url,{ headers:{ Authorization: `bearer ${token.accessToken}` } } )

If you store the token you can even refresh it without asking for user permission:

const oauth = new ClientOAuth2({ authorizationUri: `${uaaUrl}/oauth/authorize`, accessTokenUri: `${uaaUrl}/oauth/token`, redirectUri: "http://localhost/notfound", // no need to set up a server here, will not be called clientId, clientSecret }) const token = await oauth .createToken(accessToken, refreshToken, tokenType, {}) .refresh() .then(t => t.accessToken)

It’s fairly easy to find client ID, secret and UAA url, they’re in the service key of the service you are trying to access to (my abap trial shared instance in this case), but I wanted to find it programmatically, just in case one day I decided hat UX is important and code a connection wizard…

For now must be done manually:

{ "abapfs.remote": { "hanatrial": { "url": "from_servicekey-url", "username": "from_eclipse", "password": "", "client": "100", "oauth": { "clientId": "from_servicekey-uaa-clientId", "clientSecret": "from_servicekey-uaa-clientSecret", "loginUrl": "from_servicekey-uaa-url", "saveCredentials": true } } } }

This was a bit harder to figure out.

const headers = { Accept: "application/json" } // get the list of available services const sr = await got( "",{ headers ,responseType: 'json'}) const services = sr.body // get the endpoint configuration, to extract the login service URL const resp = await got("", { headers ,responseType: 'json'}) const loginUrl = resp.body.links.login.href // finally get the CF login token const token = new ClientOAuth2({ accessTokenUri: `${loginUrl}/oauth/token` })

… and then use the bearer token extracted to get:

  • organisations (`${endpoint}/v2/organizations`)
  • spaces in an organisation (`${endpoint}${organization.spaces_url}`)
  • service instances in a space `${endpoint}${space.service_instances_url}`

To figure out what service instance you’re interested on, you have lo look it up in the list of services, and then look up its guid in the service instances. Finally you can use that to get your service key:

const findAbapTag = (tags: string[]) => tags && tags.find(t => t === "abapcp") // find the service const abapService = services.find(s => findAbapTag(s.entity.tags)) // find the first service instance const abapServiceInstance = instances.find( i => i.entity.service_guid === abapService?.metadata.guid ) const headers = { Authorization: `bearer ${token..accessToken}`, Accept: "application/json" } const resp = await const resp = await got(`${abapServiceInstance.service_keys_url}`, { headers, searchParams: { q: `name:SAP_ADT` }, // Eclipse's. Should better use another responseType: 'json' }) const key

Finally, since cloud trial allows abapgit commits, I decided it was time to add those to the client 🙂

DJ Adams showed how to do most of this from the command line right after I did my own homework…