# Connecting to Microsoft Graph API Jython Code Fails

**URL:** <https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228>\
**Category:** General Discussion\
**Tags:** scripting\
**Created:** [December 16, 2023, 1:37pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228 "2023-12-16T13:37:27Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 16, 2023, 1:37pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/1 "2023-12-16T13:37:27Z")

</div>

Good morning,

I have a Microsoft developer E5 account and a custom environment to test this problem in.

I followed the steps in this video:

[![](https://us1.discourse-cdn.com/inductiveautomation/original/3X/2/5/25162dcacbd135f531d319a8b0236e783841591e.jpeg "Connecting to Microsoft Graph API with Python msal library.") ](https://www.youtube.com/watch?v=wAIZn6RDSJg)

I am using Ignition v8.1.35.

I am using the following python libraries which I already know don't all officially translate to Jython.

- msal - 1.17.0
- urllib3 - 2.1.0
- request - 2.7.0

This is the code I am testing in the script console:

```auto
import json

import requests
from msal import ConfidentialClientApplication

client_id = {client_id}"
client_secret = "{client_secret}"
tenant_id = "{tenant_id}"

msal_authority = "https://login.microsoftonline.com/" + tenant_id

msal_scope = ["https://graph.microsoft.com/.default"]

msal_app = ConfidentialClientApplication(
	client_id = client_id,
	client_credential = client_secret,
	authority = msal_authority,
	
)

result = msal_app.acquire_token_silent(
	scopes = msal_scope,
	account = None,
)

if not result:
	result = msal_app.acquire_token_for_client(scopes = msal_scope)
	
access_token = result["access_token"]

print access_token

#api_result = requests.get(
# msal_authority,
# headers={'Authorization': 'Bearer ' + access_token},
# timeout=30,
# )
#
#print api_result
```

This code gives me an access token.

However, when I go on to uncomment out the last section (use the access\_token) I get the response:

```auto
<Response [404]>
```

Does anyone know what else I can try here to display some results?

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 16, 2023, 2:08pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/2 "2023-12-16T14:08:39Z")

</div>

At the end of that video they connect to a different URL than you - why the change?

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 16, 2023, 2:50pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/3 "2023-12-16T14:50:37Z")

</div>

Oh yes, I forgot I changed stuff up while trying to get any response.

This is the updated code now...

```auto
import json

import requests
from msal import ConfidentialClientApplication

client_id ="{client_id}"
client_secret = "{client_secret}"
tenant_id = "{tenant_id}"

msal_authority = "https://login.microsoftonline.com/" + tenant_id

msal_scope = ["https://graph.microsoft.com/.default"]

msal_app = ConfidentialClientApplication(
	client_id = client_id,
	client_credential = client_secret,
	authority = msal_authority,
	
)

result = msal_app.acquire_token_silent(
	scopes = msal_scope,
	account = None,
)

if not result:
	result = msal_app.acquire_token_for_client(scopes = msal_scope)
	
access_token = result["access_token"]

print access_token

#api_result = requests.get(
# msal_authority,
# headers={'Authorization': 'Bearer ' + access_token},
# timeout=30,
# )
#

headers = {
	"Authorization":"Bearer " + access_token,
	"Content-Type": "application/json",
}

response = requests.get(
	url="https://graph.microsoft.com/v1.0/users",
	headers=headers,
)

print response

# Copy access_token and specify the MS Graph API endpoint you want to call, e.g. 'https://graph.microsoft.com/v1.0/groups' to get all groups in your organization
##access_token = '{ACCESS TOKEN YOU ACQUIRED PREVIOUSLY}'
#url = 'https://graph.microsoft.com/v1.0/groups'
#headers = {
# 'Authorization': access_token
#}
#
## Make a GET request to the provided url, passing the access token in a header
#graph_result = requests.get(url=url, headers=headers)
#
## Print the results in a JSON format
#print(graph_result.json())
```

And this is the error I get with the example:

```auto
Java Traceback:
Traceback (most recent call last):
  File "<input>", line 46, in <module>
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\api.py", line 69, in get
    return request('get', url, params=params, **kwargs)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\api.py", line 50, in request
    response = session.request(method=method, url=url, **kwargs)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\sessions.py", line 465, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\sessions.py", line 605, in send
    r.content
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 750, in content
    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 750, in content
    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 673, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 673, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 673, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 303, in stream
    for line in self.read_chunked(amt, decode_content=decode_content):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 451, in read_chunked
    yield self._decode(chunk, decode_content=decode_content,
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 192, in _decode
    data = self._decoder.decompress(data)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 192, in _decode
    data = self._decoder.decompress(data)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 58, in decompress
    return self._obj.decompress(data)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\zlib.py", line 228, in decompress
    inflated = _get_inflate_data(self.inflater, max_length)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\zlib.py", line 291, in _get_inflate_data
    l = inflater.inflate(buf)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\zlib.py", line 291, in _get_inflate_data
    l = inflater.inflate(buf)
	at java.base/java.util.zip.Inflater.ensureOpen(Unknown Source)

	at java.base/java.util.zip.Inflater.inflate(Unknown Source)

	at java.base/java.util.zip.Inflater.inflate(Unknown Source)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

	at java.base/java.lang.reflect.Method.invoke(Unknown Source)

java.lang.NullPointerException: java.lang.NullPointerException: Inflater has been closed

	at org.python.core.Py.JavaError(Py.java:545)

	at org.python.core.Py.JavaError(Py.java:536)

	at org.python.core.PyReflectedFunction. __call__ (PyReflectedFunction.java:192)

	at org.python.core.PyReflectedFunction. __call__ (PyReflectedFunction.java:208)

	at org.python.core.PyObject. __call__ (PyObject.java:477)

	at org.python.core.PyObject. __call__ (PyObject.java:481)

	at org.python.core.PyMethod. __call__ (PyMethod.java:141)

	at zlib$py._get_inflate_data$15(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/zlib.py:303)

	at zlib$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/zlib.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:150)

	at org.python.core.PyFunction. __call__ (PyFunction.java:426)

	at zlib$py.decompress$11(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/zlib.py:247)

	at zlib$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/zlib.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:141)

	at org.python.core.PyFunction. __call__ (PyFunction.java:426)

	at org.python.core.PyMethod. __call__ (PyMethod.java:141)

	at requests.packages.urllib3.response$py.decompress$8(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py:58)

	at requests.packages.urllib3.response$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:150)

	at org.python.core.PyFunction. __call__ (PyFunction.java:426)

	at org.python.core.PyMethod. __call__ (PyMethod.java:141)

	at requests.packages.urllib3.response$py._decode$18(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py:203)

	at requests.packages.urllib3.response$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:197)

	at org.python.core.PyFunction. __call__ (PyFunction.java:485)

	at org.python.core.PyMethod.instancemethod ___call__ (PyMethod.java:237)

	at org.python.core.PyMethod. __call__ (PyMethod.java:228)

	at requests.packages.urllib3.response$py.read_chunked$32(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py:466)

	at requests.packages.urllib3.response$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyGenerator. __iternext__ (PyGenerator.java:161)

	at org.python.core.PyGenerator. __iternext__ (PyGenerator.java:143)

	at requests.packages.urllib3.response$py.stream$20(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py:306)

	at requests.packages.urllib3.response$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyGenerator. __iternext__ (PyGenerator.java:161)

	at org.python.core.PyGenerator. __iternext__ (PyGenerator.java:143)

	at requests.models$py.generate$41(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/models.py:689)

	at requests.models$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/models.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyGenerator. __iternext__ (PyGenerator.java:161)

	at org.python.core.PyGenerator. __iternext__ (PyGenerator.java:143)

	at org.python.core.PySequence.fastSequence(PySequence.java:314)

	at org.python.core.PyString.str_join(PyString.java:3271)

	at org.python.core.PyString$str_join_exposer. __call__ (Unknown Source)

	at org.python.core.PyObject. __call__ (PyObject.java:465)

	at requests.models$py.content$43(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/models.py:758)

	at requests.models$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/models.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:134)

	at org.python.core.PyFunction. __call__ (PyFunction.java:416)

	at org.python.core.PyFunction. __call__ (PyFunction.java:411)

	at org.python.core.PyProperty.property ___get__ (PyProperty.java:82)

	at org.python.core.PyProperty. __get__ (PyProperty.java:71)

	at org.python.core.PyObject.object ___findattr__ (PyObject.java:3766)

	at org.python.core.Deriveds. __findattr_ex__ (Deriveds.java:43)

	at org.python.core.PyObjectDerived. __findattr_ex__ (PyObjectDerived.java:1036)

	at org.python.core.PyObject. __getattr__ (PyObject.java:957)

	at requests.sessions$py.send$21(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/sessions.py:607)

	at requests.sessions$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/sessions.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:197)

	at org.python.core.PyFunction. __call__ (PyFunction.java:485)

	at org.python.core.PyMethod.instancemethod ___call__ (PyMethod.java:237)

	at org.python.core.PyMethod. __call__ (PyMethod.java:228)

	at org.python.core.PyMethod. __call__ (PyMethod.java:223)

	at org.python.core.PyObject._callextra(PyObject.java:589)

	at requests.sessions$py.request$13(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/sessions.py:467)

	at requests.sessions$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/sessions.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:197)

	at org.python.core.PyFunction. __call__ (PyFunction.java:485)

	at org.python.core.PyMethod.instancemethod ___call__ (PyMethod.java:237)

	at org.python.core.PyMethod. __call__ (PyMethod.java:228)

	at org.python.core.PyMethod. __call__ (PyMethod.java:223)

	at org.python.core.PyObject._callextra(PyObject.java:589)

	at requests.api$py.request$1(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/api.py:55)

	at requests.api$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/api.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

	at org.python.core.PyFunction.function ___call__ (PyFunction.java:474)

	at org.python.core.PyFunction. __call__ (PyFunction.java:469)

	at org.python.core.PyFunction. __call__ (PyFunction.java:464)

	at org.python.core.PyObject._callextra(PyObject.java:589)

	at requests.api$py.get$2(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/api.py:69)

	at requests.api$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/api.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

	at org.python.core.PyFunction.function ___call__ (PyFunction.java:474)

	at org.python.core.PyFunction. __call__ (PyFunction.java:469)

	at org.python.pycode._pyx17.f$0(<input>:51)

	at org.python.pycode._pyx17.call_function(<input>)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyCode.call(PyCode.java:18)

	at org.python.core.Py.runCode(Py.java:1703)

	at org.python.core.Py.exec(Py.java:1747)

	at org.python.util.PythonInterpreter.exec(PythonInterpreter.java:277)

	at org.python.util.InteractiveInterpreter.runcode(InteractiveInterpreter.java:130)

	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:628)

	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:616)

	at java.desktop/javax.swing.SwingWorker$1.call(Unknown Source)

	at java.base/java.util.concurrent.FutureTask.run(Unknown Source)

	at java.desktop/javax.swing.SwingWorker.run(Unknown Source)

	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

	at java.base/java.lang.Thread.run(Unknown Source)

Caused by: java.lang.NullPointerException: Inflater has been closed

	at java.base/java.util.zip.Inflater.ensureOpen(Unknown Source)

	at java.base/java.util.zip.Inflater.inflate(Unknown Source)

	at java.base/java.util.zip.Inflater.inflate(Unknown Source)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

	at java.base/java.lang.reflect.Method.invoke(Unknown Source)

	at org.python.core.PyReflectedFunction. __call__ (PyReflectedFunction.java:190)

	... 111 more

Traceback (most recent call last):
  File "<input>", line 46, in <module>
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\api.py", line 69, in get
    return request('get', url, params=params, **kwargs)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\api.py", line 50, in request
    response = session.request(method=method, url=url, **kwargs)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\sessions.py", line 465, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\sessions.py", line 605, in send
    r.content
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 750, in content
    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 750, in content
    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 673, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 673, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 673, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 303, in stream
    for line in self.read_chunked(amt, decode_content=decode_content):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 451, in read_chunked
    yield self._decode(chunk, decode_content=decode_content,
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 192, in _decode
    data = self._decoder.decompress(data)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 192, in _decode
    data = self._decoder.decompress(data)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 58, in decompress
    return self._obj.decompress(data)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\zlib.py", line 228, in decompress
    inflated = _get_inflate_data(self.inflater, max_length)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\zlib.py", line 291, in _get_inflate_data
    l = inflater.inflate(buf)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\zlib.py", line 291, in _get_inflate_data
    l = inflater.inflate(buf)
	at java.base/java.util.zip.Inflater.ensureOpen(Unknown Source)

	at java.base/java.util.zip.Inflater.inflate(Unknown Source)

	at java.base/java.util.zip.Inflater.inflate(Unknown Source)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

	at java.base/java.lang.reflect.Method.invoke(Unknown Source)

java.lang.NullPointerException: java.lang.NullPointerException: Inflater has been closed
```

It was mad about something with zlib.py and that is when I started looking into older versions of the libraries and then things just got worse so I posted here looking for any advice/input.

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 17, 2023, 3:28pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/4 "2023-12-17T15:28:32Z")

</div>

After updating to requests 2.11.1 I was able to get a valid response. Proceeding to try and interact with TEAMs...

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 18, 2023, 3:36pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/5 "2023-12-18T15:36:12Z")

</div>

So after getting another step further I think I have hit a dead end in sending messages to Microsoft Teams one-on-one chats.

TL:DR - Not possible without delegated permissions.

```auto
import json

import requests
from msal import ConfidentialClientApplication

client_id = "{client_id}"
client_secret = "{client_secret}"
tenant_id = "{tenant_id}"

msal_authority = "https://login.microsoftonline.com/" + tenant_id

msal_scope = ["https://graph.microsoft.com/.default"]

msal_app = ConfidentialClientApplication(
	client_id = client_id,
	client_credential = client_secret,
	authority = msal_authority,
	
)

result = msal_app.acquire_token_silent(
	scopes = msal_scope,
	account = None,
)

if not result:
	result = msal_app.acquire_token_for_client(scopes = msal_scope)
	
access_token = result["access_token"]

print access_token

url = 'https://graph.microsoft.com/v1.0/teams/{teams_id}/channels/{channel_id}/messages'
headers = {
  'Authorization': access_token
}
data = {
    "body": {
        "content": "Hello world"
    }
}

graph_result = requests.post(url=url, json=data, headers=headers)

print(graph_result.json())
```

And the resulting error is:

```auto
{u'error': {u'code': u'Unauthorized', u'message': u'Message POST is allowed in application-only context only for import purposes. Refer to https://docs.microsoft.com/microsoftteams/platform/graph-api/import-messages/import-external-messages-to-teams for more details.', u'innerError': {u'date': u'2023-12-18T14:59:24', u'request-id': u'{request_id}', u'client-request-id': u'{client_request_id}'}}}
```

Which means I don't have delegated permissions from Ignition. I am a bit stuck here but looks like my potential options are:

1. Use a webhook to send messages to a channel, create a bot to distribute the messages to individual users.

> **[Build notification bot with JavaScript - Teams](https://learn.microsoft.com/en-us/microsoftteams/platform/sbs-gs-notificationbot?tabs=vscode&tutorial-step=1)**
>
> In this tutorial, you can learn to send notification by creating a new notification bot with Teams Toolkit.

1. Use a webhook to create necessary channels, register the channels with Ignition, and POST messages accordingly to the channel (users can "subscribe" to whatever channel they need then.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 18, 2023, 3:41pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/6 "2023-12-18T15:41:43Z")

</div>

What are you ultimately trying to achieve?

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 18, 2023, 3:45pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/7 "2023-12-18T15:45:17Z")

</div>

I wanted Ignition to send one-on-one chats to Microsoft TEAMs users to alert them that a specific workstation on the floor was requesting help [using the webdev module].

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 18, 2023, 3:46pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/8 "2023-12-18T15:46:19Z")

</div>

> [@bmeyers](#):
>
> a specific workstation on the floor was requesting help

That sounds pretty cool, actually. Please continue blazing a trail for the rest of us. 😁

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 18, 2023, 3:52pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/9 "2023-12-18T15:52:50Z")

</div>

Hmm, based on a quick scan of those docs it sounds like you need to build a "bot".

I'm not sure the WebDev module is relevant here.

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 18, 2023, 3:54pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/10 "2023-12-18T15:54:58Z")

</div>

Can I call webhooks without the webdev module?

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 18, 2023, 3:55pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/11 "2023-12-18T15:55:15Z")

</div>

Making HTTP requests does not require WebDev.

Receiving inbound HTTP requests does.

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 18, 2023, 3:56pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/12 "2023-12-18T15:56:45Z")

</div>

Oh yes... I was confused. Too early in the week for thinking 😃

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 18, 2023, 7:01pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/13 "2023-12-18T19:01:45Z")

</div>

It appears that Microsoft Teams allows someone to make a bot that can handle various incoming POSTs and I'll post the full tutorial when I finish.

Curiously though I can't get system.net.httpClient to work as expected. I have gotten results using the requests library and the system.net.httpPost function. Any idea what my code for httpClient is missing?

```auto
#
# This code works
import requests

url = 'http://localhost:3978/api/notification'
headers = {'Content-Type' : 'application/json'}
data = {}

results = requests.post(url=url, json=data, headers=headers)

print results
```

```auto
# This code works.
url = 'http://localhost:3978/api/notification'

response = system.net.httpPost(url)

print response
```

```auto
# This code has not worked yet.
client = system.net.httpClient()

url = 'http://localhost:3978/api/notification'
#headers = {'Content-Type' : 'application/json'}
#data = {}

response = client.post(url=url)

print response
```

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 18, 2023, 7:07pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/14 "2023-12-18T19:07:08Z")

</div>

I mean... as you've provided it, you're not posting any data.

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 18, 2023, 7:10pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/15 "2023-12-18T19:10:09Z")

</div>

I mean that is technically true... however I am also not posting any data when using system.net.httpPost and that example works for me.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/3/7/372c92e008ead1d9ca8de23cea595d49063de7d3.png)

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 18, 2023, 7:14pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/16 "2023-12-18T19:14:44Z")

</div>

I don't know, use Wireshark to spy on the traffic to the localhost webserver and see what's different.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [December 18, 2023, 7:22pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/17 "2023-12-18T19:22:33Z")

</div>

Sending an empty data dictionary in `httpClient` should automatically set the content type to `application/json`. Make sure you're passing it with keyword arguments?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 18, 2023, 7:32pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/18 "2023-12-18T19:32:32Z")

</div>

Also, make sure you cache your `httpClient` instance--they are meant to be re-used, and will leak memory if you keep making more.

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 18, 2023, 10:33pm UTC](https://forum.inductiveautomation.com/t/connecting-to-microsoft-graph-api-jython-code-fails/83228/19 "2023-12-18T22:33:46Z")

</div>

Using httpPost -

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/9/1/91a808e0aa1dab458bff4b0b65d2bbb497b0ffff.png)

And using httpClient -

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/a/8/a8e86bbdd50c65ecbb1e40dc5e8688283959cf0f.png)

It appears that httpClient defaults to version HTTP\_2 while httpPost is using HTTP\_1\_1. By setting the version in my httpClient call to HTTP\_1\_1 I was able to get a result.

```auto
# This code works with version specified HTTP_1_1.
client = system.net.httpClient(version='HTTP_1_1')

url = 'http://localhost:3978/api/notification'

response = client.post(url=url)

print response
```
