CharlesO
Doing JWT by hand for Microsoft Teams Bot / understanding how to use Elixir JWT libraries for this scenario
Hi.
I’m trying to handle Microsoft Teams Bot Authentication by hand, as it seems less confusing than trying to adapt an existing `JWT library, (it’s also a good way to understand JWTs in general).
I use the Microsoft Bot Emulator - and so far so good until I had to create/ validate JWTs.
The main issue is, that I don’t know how to derive a secret that is used to do the HMAC signature.
This is an actual Authorization header:
authorization: "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjJaUXBKM1VwYmpBWVhZR2FYRUpsOGxWMFRPSSJ9.eyJhdWQiOiI2YjMyNmY1Mi1lY2NhLTQ4OTQtYWJmYi00ZWFhYmMxYTM0ZTUiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vZDZkNDk0MjAtZjM5Yi00ZGY3LWExZGMtZDU5YTkzNTg3MWRiL3YyLjAiLCJpYXQiOjE2NjAwMTQzMTUsIm5iZiI6MTY2MDAxNDMxNSwiZXhwIjoxNjYwMTAxMDE1LCJhaW8iOiJFMlpnWUlpeDJSRXFWL3VLL3o5WEJOc3k0MmVtQUE9PSIsImF6cCI6IjZiMzI2ZjUyLWVjY2EtNDg5NC1hYmZiLTRlYWFiYzFhMzRlNSIsImF6cGFjciI6IjEiLCJyaCI6IjAuQVc0QUlKVFUxcHZ6OTAyaDNOV2FrMWh4MjFKdk1tdks3SlJJcV90T3Fyd2FOT1Z1QUFBLiIsInRpZCI6ImQ2ZDQ5NDIwLWYzOWItNGRmNy1hMWRjLWQ1OWE5MzU4NzFkYiIsInV0aSI6IjVJdDNJMFFZVVVXVVVRN2hqZnVTQUEiLCJ2ZXIiOiIyLjAifQ.u-AQYlMlIIZaOe-e-jLlyo94NIH0UITHZELl7F0MRG1WAFO6SKabMrdY0jh82ZsdwS1hDhT8nwOyRKLu4FKjmNwndZFM-AoKbTU48aevSO4Xl3ktKHs7TDGNy7qDr1cAQl0IiBivkIbq6_KZTF5Qhs4Q_RIQdRJdqYDCp691aH3i4rxy-xU_EpRJlhElxG8oyplACitoyM8EZITmr0Zr2v3R0EffypV1PeGTwmotB0kYclzkr14szMh5cAmwsuxxQT4g18_340VAg_P68Fne-_XfXE9SyDgR_s5AqZWewm0Ef54usoMVjQI44JWi2r98IlHeajp_Lf4dUWGN9PLzSw
This is the relevant key for that header, taken from here:
https://login.microsoftonline.com/d6d49420-f39b-4df7-a1dc-d59a935871db/discovery/v2.0/keys
{
"kty": "RSA",
"use": "sig",
"kid": "2ZQpJ3UpbjAYXYGaXEJl8lV0TOI",
"x5t": "2ZQpJ3UpbjAYXYGaXEJl8lV0TOI",
"n": "wEMMJtj9yMQd8QS6Vnm538K5GN1Pr_I31_LUl9-OCYu-9_DrDvPGjViQK9kOiCjBfyqoAL-pBecn9-XXaS-C4xZTn1ZRw--GELabuo0u-U6r3TKj42xFDEP-_R5RpOGshoC95lrKiU5teuhn4fBM3XfR2GB0dVMcpzN3h4-0OMvBK__Zr9tkQCU_KzXTbNCjyA7ybtbr83NF9k3KjpTyOyY2S-qvFbY-AoqMhL9Rp8r2HBj_vrsr6RX6GeiSxxjbEzDFA2VIcSKbSHvbNBEeW2KjLXkz6QG2LjKz5XsYLp6kv_-k9lPQBy_V7Ci4ZkhAN-6j1S1Kcq58aLbp0wDNKQ",
"e": "AQAB",
"x5c": [
"MIIDBTCCAe2gAwIBAgIQH4FlYNA+UJlF0G3vy9ZrhTANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTIyMDUyMjIwMDI0OVoXDTI3MDUyMjIwMDI0OVowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBDDCbY/cjEHfEEulZ5ud/CuRjdT6/yN9fy1JffjgmLvvfw6w7zxo1YkCvZDogowX8qqAC/qQXnJ/fl12kvguMWU59WUcPvhhC2m7qNLvlOq90yo+NsRQxD/v0eUaThrIaAveZayolObXroZ+HwTN130dhgdHVTHKczd4ePtDjLwSv/2a/bZEAlPys102zQo8gO8m7W6/NzRfZNyo6U8jsmNkvqrxW2PgKKjIS/UafK9hwY/767K+kV+hnokscY2xMwxQNlSHEim0h72zQRHltioy15M+kBti4ys+V7GC6epL//pPZT0Acv1ewouGZIQDfuo9UtSnKufGi26dMAzSkCAwEAAaMhMB8wHQYDVR0OBBYEFLFr+sjUQ+IdzGh3eaDkzue2qkTZMA0GCSqGSIb3DQEBCwUAA4IBAQCiVN2A6ErzBinGYafC7vFv5u1QD6nbvY32A8KycJwKWy1sa83CbLFbFi92SGkKyPZqMzVyQcF5aaRZpkPGqjhzM+iEfsR2RIf+/noZBlR/esINfBhk4oBruj7SY+kPjYzV03NeY0cfO4JEf6kXpCqRCgp9VDRM44GD8mUV/ooN+XZVFIWs5Gai8FGZX9H8ZSgkIKbxMbVOhisMqNhhp5U3fT7VPsl94rilJ8gKXP/KBbpldrfmOAdVDgUC+MHw3sSXSt+VnorB4DU4mUQLcMriQmbXdQc8d1HUZYZEkcKaSgbygHLtByOJF44XUsBotsTfZ4i/zVjnYcjgUQmwmAWD"
],
"issuer": "https://login.microsoftonline.com/d6d49420-f39b-4df7-a1dc-d59a935871db/v2.0"
}
I don’t know how to get a usable secret to perform the signature part of the JWT process, or how to apply it to any of the Elixir JWT libraries.
Any direction is much appreciated. Thanks!
Marked As Solved
thomas.fortes
Your code above sends Bearer some_token_here, I was talking about just Bearer, no token at all
Also Liked
thomas.fortes
It isn’t using HMAC, it is using RSA, to verify it using Joken you can do something like:
bearer = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjJaUXBKM1VwYmpBWVhZR2FYRUpsOGxWMFRPSSJ9.eyJhdWQiOiI2YjMyNmY1Mi1lY2NhLTQ4OTQtYWJmYi00ZWFhYmMxYTM0ZTUiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vZDZkNDk0MjAtZjM5Yi00ZGY3LWExZGMtZDU5YTkzNTg3MWRiL3YyLjAiLCJpYXQiOjE2NjAwMTQzMTUsIm5iZiI6MTY2MDAxNDMxNSwiZXhwIjoxNjYwMTAxMDE1LCJhaW8iOiJFMlpnWUlpeDJSRXFWL3VLL3o5WEJOc3k0MmVtQUE9PSIsImF6cCI6IjZiMzI2ZjUyLWVjY2EtNDg5NC1hYmZiLTRlYWFiYzFhMzRlNSIsImF6cGFjciI6IjEiLCJyaCI6IjAuQVc0QUlKVFUxcHZ6OTAyaDNOV2FrMWh4MjFKdk1tdks3SlJJcV90T3Fyd2FOT1Z1QUFBLiIsInRpZCI6ImQ2ZDQ5NDIwLWYzOWItNGRmNy1hMWRjLWQ1OWE5MzU4NzFkYiIsInV0aSI6IjVJdDNJMFFZVVVXVVVRN2hqZnVTQUEiLCJ2ZXIiOiIyLjAifQ.u-AQYlMlIIZaOe-e-jLlyo94NIH0UITHZELl7F0MRG1WAFO6SKabMrdY0jh82ZsdwS1hDhT8nwOyRKLu4FKjmNwndZFM-AoKbTU48aevSO4Xl3ktKHs7TDGNy7qDr1cAQl0IiBivkIbq6_KZTF5Qhs4Q_RIQdRJdqYDCp691aH3i4rxy-xU_EpRJlhElxG8oyplACitoyM8EZITmr0Zr2v3R0EffypV1PeGTwmotB0kYclzkr14szMh5cAmwsuxxQT4g18_340VAg_P68Fne-_XfXE9SyDgR_s5AqZWewm0Ef54usoMVjQI44JWi2r98IlHeajp_Lf4dUWGN9PLzSw"
signer_json = ~s(
{
"kty": "RSA",
"use": "sig",
"kid": "2ZQpJ3UpbjAYXYGaXEJl8lV0TOI",
"x5t": "2ZQpJ3UpbjAYXYGaXEJl8lV0TOI",
"n": "wEMMJtj9yMQd8QS6Vnm538K5GN1Pr_I31_LUl9-OCYu-9_DrDvPGjViQK9kOiCjBfyqoAL-pBecn9-XXaS-C4xZTn1ZRw--GELabuo0u-U6r3TKj42xFDEP-_R5RpOGshoC95lrKiU5teuhn4fBM3XfR2GB0dVMcpzN3h4-0OMvBK__Zr9tkQCU_KzXTbNCjyA7ybtbr83NF9k3KjpTyOyY2S-qvFbY-AoqMhL9Rp8r2HBj_vrsr6RX6GeiSxxjbEzDFA2VIcSKbSHvbNBEeW2KjLXkz6QG2LjKz5XsYLp6kv_-k9lPQBy_V7Ci4ZkhAN-6j1S1Kcq58aLbp0wDNKQ",
"e": "AQAB",
"x5c": [
"MIIDBTCCAe2gAwIBAgIQH4FlYNA+UJlF0G3vy9ZrhTANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTIyMDUyMjIwMDI0OVoXDTI3MDUyMjIwMDI0OVowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBDDCbY/cjEHfEEulZ5ud/CuRjdT6/yN9fy1JffjgmLvvfw6w7zxo1YkCvZDogowX8qqAC/qQXnJ/fl12kvguMWU59WUcPvhhC2m7qNLvlOq90yo+NsRQxD/v0eUaThrIaAveZayolObXroZ+HwTN130dhgdHVTHKczd4ePtDjLwSv/2a/bZEAlPys102zQo8gO8m7W6/NzRfZNyo6U8jsmNkvqrxW2PgKKjIS/UafK9hwY/767K+kV+hnokscY2xMwxQNlSHEim0h72zQRHltioy15M+kBti4ys+V7GC6epL//pPZT0Acv1ewouGZIQDfuo9UtSnKufGi26dMAzSkCAwEAAaMhMB8wHQYDVR0OBBYEFLFr+sjUQ+IdzGh3eaDkzue2qkTZMA0GCSqGSIb3DQEBCwUAA4IBAQCiVN2A6ErzBinGYafC7vFv5u1QD6nbvY32A8KycJwKWy1sa83CbLFbFi92SGkKyPZqMzVyQcF5aaRZpkPGqjhzM+iEfsR2RIf+/noZBlR/esINfBhk4oBruj7SY+kPjYzV03NeY0cfO4JEf6kXpCqRCgp9VDRM44GD8mUV/ooN+XZVFIWs5Gai8FGZX9H8ZSgkIKbxMbVOhisMqNhhp5U3fT7VPsl94rilJ8gKXP/KBbpldrfmOAdVDgUC+MHw3sSXSt+VnorB4DU4mUQLcMriQmbXdQc8d1HUZYZEkcKaSgbygHLtByOJF44XUsBotsTfZ4i/zVjnYcjgUQmwmAWD"
],
"issuer": "https://login.microsoftonline.com/d6d49420-f39b-4df7-a1dc-d59a935871db/v2.0"
}
)
signer_key = signer_json |> Jason.decode!()
signer = Joken.Signer.create("RS256", signer_key)
# {:ok, payload} for success, {:error, :signature_error} for failure
token = Joken.verify(bearer, signer)
al2o3cr
The key material supplied (in the "x5c" key of signer_json) only includes the public key; you can’t sign things with it, only verify that a request from Microsoft’s servers is genuine.
I don’t see any requirement to sign outgoing data in the linked documentation. Requests to Discord fetch an already-signed JWT from Azure AD and include it in Authorization headers, while requests from Discord include an already-signed JWT as well.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









