# HG changeset patch # User Kim Alvefur # Date 1693053424 -7200 # Node ID b3484a112300102637d9b28fbc180cff4655549e # Parent 401356232e1beac0c98ed20d6308311c9b112854 mod_rest/rest.sh: Update to use httpie-oauth2 plugin This bash implementation of OAuth2/OIDC was growing to the point where it needed a massive refactor, which made me look into alternatives where I finally settled on implementing oauth2 in a plugin for HTTPie. diff -r 401356232e1b -r b3484a112300 mod_rest/example/rest.sh --- a/mod_rest/example/rest.sh Sat Aug 26 01:40:23 2023 +0200 +++ b/mod_rest/example/rest.sh Sat Aug 26 14:37:04 2023 +0200 @@ -5,23 +5,23 @@ # Dependencies: # - https://httpie.io/ -# - https://github.com/stedolan/jq -# - some sort of XDG 'open' command +# - https://hg.sr.ht/~zash/httpie-oauth2 # Settings HOST="" DOMAIN="" -AUTH_METHOD="session-read-only" -AUTH_ID="rest" - if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/restrc" ]; then # Config file can contain the above settings source "${XDG_CONFIG_HOME:-$HOME/.config}/restrc" + + if [ -z "${SCOPE:-}" ]; then + SCOPE="openid xmpp" + fi fi if [[ $# == 0 ]]; then - echo "${0##*/} [-h HOST] [-u USER|--login] [/path] kind=(message|presence|iq) ...." + echo "${0##*/} [-h HOST] [/path] kind=(message|presence|iq) ...." # Last arguments are handed to HTTPie, so refer to its docs for further details exit 0 fi @@ -45,96 +45,6 @@ fi fi -if [[ "$1" == "-u" ]]; then - # -u username - AUTH_METHOD="auth" - AUTH_ID="$2" - shift 2 -elif [[ "$1" == "-rw" ]]; then - # To e.g. save Accept headers to the session - AUTH_METHOD="session" - shift 1 -fi - -if [[ "$1" == "--login" ]]; then - shift 1 - - # Check cache for OAuth client - if [ -f "${XDG_CACHE_HOME:-$HOME/.cache}/rest/$HOST" ]; then - source "${XDG_CACHE_HOME:-$HOME/.cache}/rest/$HOST" - fi - - OAUTH_META="$(http --check-status --json "https://$HOST/.well-known/oauth-authorization-server" Accept:application/json)" - AUTHORIZATION_ENDPOINT="$(echo "$OAUTH_META" | jq -e -r '.authorization_endpoint')" - TOKEN_ENDPOINT="$(echo "$OAUTH_META" | jq -e -r '.token_endpoint')" - - if [ -z "${OAUTH_CLIENT_INFO:-}" ]; then - # Register a new OAuth client - REGISTRATION_ENDPOINT="$(echo "$OAUTH_META" | jq -e -r '.registration_endpoint')" - OAUTH_CLIENT_INFO="$(http --check-status "$REGISTRATION_ENDPOINT" Content-Type:application/json Accept:application/json client_name=rest.sh client_uri="https://modules.prosody.im/mod_rest" application_type=native software_id=0bdb0eb9-18e8-43af-a7f6-bd26613374c0 redirect_uris:='["urn:ietf:wg:oauth:2.0:oob"]')" - mkdir -p "${XDG_CACHE_HOME:-$HOME/.cache}/rest/" - typeset -p OAUTH_CLIENT_INFO >> "${XDG_CACHE_HOME:-$HOME/.cache}/rest/$HOST" - fi - - CLIENT_ID="$(echo "$OAUTH_CLIENT_INFO" | jq -e -r '.client_id')" - CLIENT_SECRET="$(echo "$OAUTH_CLIENT_INFO" | jq -e -r '.client_secret')" - - if [ -n "${REFRESH_TOKEN:-}" ]; then - TOKEN_RESPONSE="$(http --check-status --form "$TOKEN_ENDPOINT" 'grant_type=refresh_token' "client_id=$CLIENT_ID" "client_secret=$CLIENT_SECRET" "refresh_token=$REFRESH_TOKEN")" - ACCESS_TOKEN="$(echo "$TOKEN_RESPONSE" | jq -r '.access_token')" - if [ "$ACCESS_TOKEN" == "null" ]; then - ACCESS_TOKEN="" - fi - fi - - if [ -z "${ACCESS_TOKEN:-}" ]; then - CODE_CHALLENGE="$(head -c 33 /dev/urandom | base64 | tr /+ _-)" - open "$AUTHORIZATION_ENDPOINT?response_type=code&client_id=$CLIENT_ID&code_challenge=$CODE_CHALLENGE&scope=${SCOPE:-openid+prosody:user}" - read -p "Paste authorization code: " -s -r AUTHORIZATION_CODE - - TOKEN_RESPONSE="$(http --check-status --form "$TOKEN_ENDPOINT" 'grant_type=authorization_code' "client_id=$CLIENT_ID" "client_secret=$CLIENT_SECRET" "code=$AUTHORIZATION_CODE" code_verifier="$CODE_CHALLENGE")" - ACCESS_TOKEN="$(echo "$TOKEN_RESPONSE" | jq -e -r '.access_token')" - REFRESH_TOKEN="$(echo "$TOKEN_RESPONSE" | jq -r '.refresh_token')" - - if [ "$REFRESH_TOKEN" != "null" ]; then - # FIXME Better type check would be nice, but nobody should ever have the - # string "null" as a legitimate refresh token... - typeset -p REFRESH_TOKEN >> "${XDG_CACHE_HOME:-$HOME/.cache}/rest/$HOST" - fi - - if [ -n "${COLORTERM:-}" ]; then - echo -ne '\e[1K\e[G' - else - echo - fi - fi - - USERINFO_ENDPOINT="$(echo "$OAUTH_META" | jq -e -r '.userinfo_endpoint')" - http --check-status -b --session rest "$USERINFO_ENDPOINT" "Authorization:Bearer $ACCESS_TOKEN" Accept:application/json >&2 - AUTH_METHOD="session-read-only" - AUTH_ID="rest" - -elif [[ "$1" == "--logout" ]]; then - # Revoke token - source "${XDG_CACHE_HOME:-$HOME/.cache}/rest/$HOST" - - OAUTH_META="$(http --check-status --json "https://$HOST/.well-known/oauth-authorization-server" Accept:application/json)" - REVOCATION_ENDPOINT="$(echo "$OAUTH_META" | jq -e -r '.revocation_endpoint')" - - CLIENT_ID="$(echo "$OAUTH_CLIENT_INFO" | jq -e -r '.client_id')" - CLIENT_SECRET="$(echo "$OAUTH_CLIENT_INFO" | jq -e -r '.client_secret')" - - http -h --check-status --auth "$CLIENT_ID:$CLIENT_SECRET" --form "$REVOCATION_ENDPOINT" token="$REFRESH_TOKEN" - - # Overwrite the token - typeset -p OAUTH_CLIENT_INFO > "${XDG_CACHE_HOME:-$HOME/.cache}/rest/$HOST" - exit 0 -fi - -if [[ $# == 0 ]]; then - # Just login? - exit 0 -fi # For e.g /disco/example.com and such GET queries GET_PATH="" @@ -143,4 +53,4 @@ shift 1 fi -http --check-status -p b "--$AUTH_METHOD" "$AUTH_ID" "https://$HOST/rest$GET_PATH" "$@" +https --check-status -p b --session rest -A oauth2 -a "$HOST" --oauth2-scope "$SCOPE" "$HOST/rest$GET_PATH" "$@"