Command line utility to get an OAuth access token for three-legged flows where you authorise an application to access your account. Inspired by oauth2-cli written in Go.
The reason for rewriting this in Ruby was the difficulty to debug the OAuth2 flow when things don't go as expected. Go's OAuth2 library is pretty opaque and trying to figure out why for some services the client_id is not passed when sending the the token request after obtaining the authorisation code has been fruitless - even though sending the request via curl using the produced authorisation code proved successful.
The purpose for this tool is to obtain access and refresh tokens for applications which run as services (e.g daemons) where doing the OAuth2 flow is a bit difficult. However, the scope is not limited to just this. For this use case, the client_credentials
grant type would be more appropriate, but unfortunately not all API providers support this because they make the rather wrong assumption that all apps are used interactively. They only support authorization_code
grant type or worse, password
grant type.
gem install oauth2-cli
For services which validate the callback URL, you must use http://127.0.0.1:8000/oauth/callback
in your OAuth2 application. Bear in mind that 8000
is the default port which may be changed via CLI argument. 127.0.0.1
is the default host which may be changed via CLI argument. Adapt as necessary.
The oauth2-cli
script has a built in help:
oauth2-cli --help
Usage: oauth2-cli --auth AUTHORISATION_URL --token TOKEN_URL --id CLIENT_ID --secret CLIENT_SECRET
-a, --auth AUTHORISATION_URL Authorisation URL (required)
-t, --token TOKEN_URL Token URL (required)
-i, --id CLIENT_ID Client ID (required)
-s, --secret CLIENT_SECRET Client secret (required)
-o, --scope SCOPE1,SCOPE2,etc OAuth2 scope to authorise (not used if not specified)
-e, --separator SEPARATOR OAuth2 scope separator character (defaults to space) n.b the scope arg is always passed as array and joined with the separator char for the request
-h, --host 127.0.0.1 Callback host (defaults to 127.0.0.1) n.b this allows you to run this tool on a remote machine and have the authorisation code go there; the callback HTTP server always binds to all available network interfaces irrespective of this value
-p, --port 8000 Callback port (defaults to 8000)
-w, --write Write the returned token as JSON using TOKEN_URL host as filename with the current working directory being the destination
-u, --audience AUDIENCE The token audience, not used if unspecified (optional)
-d, --debug Turn on OAuth2 library debug and WEBrick log
The scope separator character has been implemented for services which interpret the OAuth2 spec a tad different - for example Facebook is using comma separated values for scope.
# request tokens for accessing Netatmo Weather station
oauth2-cli -a https://api.netatmo.com/oauth2/authorize -t https://api.netatmo.com/oauth2/token -i CLIENT_ID -s CLIENT_SECRET -o read_station
Go to URL: https://api.netatmo.com/oauth2/authorize?access_type=offline&client_id=CLIENT_ID&redirect_uri=http%3A%2F%2F127.0.0.1%3A8000%2Foauth%2Fcallback&response_type=code&scope=read_station&state=ewcxkqpsfrinhgvyamzbouljtd
Starting server - use Ctrl+C to stop
{"scope"=>["read_station"],
"expire_in"=>10800,
:access_token=>"ACCESS_TOKEN",
:refresh_token=>"REFRESH_TOKEN",
:expires_at=>TIMESTAMP}
^C
# request tokens for accessing Awair air-quality monitor
oauth2-cli -a https://oauth-login.awair.is -t https://oauth2.awair.is/v2/token -i CLIENT_ID -s CLIENT_SECRET
Go to URL: https://oauth-login.awair.is?access_type=offline&client_id=CLIENT_ID&redirect_uri=http%3A%2F%2F127.0.0.1%3A8000%2Foauth%2Fcallback&response_type=code&state=jtiznuypwqfhbvmradlgkeoxcs
Starting server - use Ctrl+C to stop
{"token_type"=>"Bearer",
:access_token=>"ACCESS_TOKEN",
:refresh_token=>"REFRESH_TOKEN",
:expires_at=>nil}
^C
The output hash from the token request may be used by Ruby's OAuth2 library to recreate an AccessToken
object using the from_hash
class method. You have to implement your own token refresh capabilities when the access token expires for the OAuth2 library doesn't provide such functionality.