Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- [Policy engine](./topics/policy.md)
- [Authorization and sessions](./topics/authorization.md)
- [Use the Admin API](./topics/admin-api.md)
- [Get an access token](./topics/access-token.md)

# Reference

Expand Down
31 changes: 31 additions & 0 deletions docs/topics/access-token.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Get an access token

The [Matrix Authentication Service repository contains a simple shell script](https://github.com/element-hq/matrix-authentication-service/blob/main/misc/device-code-grant.sh) to get interatively get an access token with arbitrary scopes.
It requires `sh`, `jq` and `curl` to be installed.
This can be run from anywhere, not necessarily from the host where MAS is running.

```sh
sh ./misc/device-code-grant.sh [synapse-url] <scope>...
```

This will prompt you to open a URL in your browser, finish the authentication flow, and print the access token.

This can be used to get access to the MAS admin API:

```sh
sh ./misc/device-code-grant.sh https://synapse.example.com/ urn:mas:admin
```

Or to the Synapse admin API:

```sh
sh ./misc/device-code-grant.sh https://synapse.example.com/ urn:matrix:org.matrix.msc2967.client:api:* urn:synapse:admin:*
```

Or even both at the same time:

```sh
sh ./misc/device-code-grant.sh https://synapse.example.com/ urn:matrix:org.matrix.msc2967.client:api:* urn:mas:admin urn:synapse:admin:*
```

Note that the token will be valid for a short time (5 minutes by default) and needs to be revoked manually from the MAS user interface.
110 changes: 110 additions & 0 deletions misc/device-code-grant.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/bin/sh

set -eu

usage() {
echo "$0 [synapse-url] <scope>..." >&2
exit 1
}

req() {
METHOD="$1"
shift
URL="$1"
shift
printf "> %4s %s\n" "$METHOD" "$URL" >&2
curl -sL --fail-with-body -o- -H 'Accept: application/json' -X "$METHOD" "$@" "$URL"
}

if [ "$#" -eq "0" ]; then
usage
fi

CS_API="${1%/}"
shift

if [ -z "$*" ]; then
SCOPE="urn:matrix:org.matrix.msc2967.client:api:*"
else
SCOPE="$*"
fi


echo "Discovering the homeserver endpoints"
METADATA="$(req GET "${CS_API}/_matrix/client/unstable/org.matrix.msc2965/auth_metadata")"
DEVICE_AUTHORIZATION_ENDPOINT="$(echo "$METADATA" | jq -r '.device_authorization_endpoint')"
TOKEN_ENDPOINT="$(echo "$METADATA" | jq -r '.token_endpoint')"
REGISTRATION_ENDPOINT="$(echo "$METADATA" | jq -r '.registration_endpoint')"

echo "Registering the client"
# Note that the client_uri is only used as an identifier, MAS will not try to contact this URI
RESP="$(
req POST "${REGISTRATION_ENDPOINT}" \
-H 'Content-Type: application/json' \
-d @- <<EOF
{
"client_name": "CLI tool",
"client_uri": "https://github.com/element-hq/matrix-authentication-service/",
"grant_types": ["urn:ietf:params:oauth:grant-type:device_code"],
"application_type": "native",
"token_endpoint_auth_method": "none"
}
EOF
)"

CLIENT_ID="$(echo "$RESP" | jq -r '.client_id')"

DEVICE_GRANT="$(
req POST "${DEVICE_AUTHORIZATION_ENDPOINT}" \
--data-urlencode "client_id=${CLIENT_ID}" \
--data-urlencode "scope=${SCOPE}"
)"

cat - <<EOF
-----------------------
Homeserver: ${CS_API}
Registration endpoint: ${REGISTRATION_ENDPOINT}
Device auth endpoint: ${DEVICE_AUTHORIZATION_ENDPOINT}
Token endpoint: ${TOKEN_ENDPOINT}
Client ID: ${CLIENT_ID}
Scope: ${SCOPE}
-----------------------
EOF

echo
echo "Open the following URL in your browser:"
echo "$DEVICE_GRANT" | jq -r ".verification_uri_complete"
echo

# If we have qrencode
if command -v qrencode 2>/dev/null; then
echo "$DEVICE_GRANT" | jq -r ".verification_uri_complete" | qrencode -t ANSI256UTF8
echo
fi

echo "Alternatively, go to $(echo "$DEVICE_GRANT" | jq -r ".verification_uri") and enter the code $(echo "$DEVICE_GRANT" | jq -r ".user_code")"
echo
echo -----------------------
echo

DEVICE_CODE="$(echo "$DEVICE_GRANT" | jq -r ".device_code")"
INTERVAL="$(echo "$DEVICE_GRANT" | jq -r ".interval")"

while true; do
DEVICE_RESP="$(
req POST "${TOKEN_ENDPOINT}" \
--data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
--data-urlencode "device_code=${DEVICE_CODE}" \
--data-urlencode "client_id=${CLIENT_ID}" || true
)"
if [ "$(echo "$DEVICE_RESP" | jq -r ".error")" = "authorization_pending" ]; then
echo "Waiting for authorization"
sleep "${INTERVAL}"
else
break
fi
done

echo "$DEVICE_RESP" | jq .

exit 0
Loading