Developers Guide
RPort OAuth has implemented support for sign-in via three of the main OAuth web identity providers (github, microsoft and google). This allows RPort users to sign-in with their credentials for these services.
While RPort is providing the technology, RPort administrators must setup and configured these
services to enable use by rportd
. For more information, see the Configuration Settings
and the individual provider sections.
The sections below describe how to use the RPort APIs to sign in users via an OAuth provider and obtain an RPort JWT bearer token which can then be used to login to RPort.
As mentioned previously, the RPort APIs can be configured to use either an OAuth style web app or device flows, or both together.
To determine which provider has been configured, the /auth/provider
endpoint can be called.
curl -s "http://localhost:3000/api/v1/auth/provider" | jq
This will return a response similar to the below:
{
"data": {
"auth_provider": "github",
"settings_uri": "/api/v1/auth/ext/settings",
"device_settings_uri": "/api/v1/auth/ext/settings/device"
}
}
The auth_provider
value contains the OAuth provider in use. This can be used to let the user
know which auth provider they will be signing in with.
The settings_uri
indicates an endpoint which returns values required to proceed with an individual
sign-in for a user via the web app style flow. Note that the settings_uri
returns a state
value
with a limited lifetime. It is therefore highly recommended that the settings are obtained after
the user has pressed a sign-in button.
The device_settings_uri
indicates an endpoint which returns values required to proceed with a sign-in via
the device style flow. Note that the device_settings_uri
returns values per authorization, so must
be called for each user sign-in.
To initiate the user sign-in after a login or similar button has been pressed, the /auth/ext/settings
endpoint (as returned by the /auth/provider
endpoint) must be called.
curl -s "http://localhost:3000/api/v1/auth/ext/settings" | jq
This will return a response similar to the below:
{
"data": {
"auth_provider": "github",
"details": {
"message": "Please authenticate on the authorize_url and submit via GET the code and state values returned by the auth provider to the login_uri",
"authorize_url": "https://github.com/login/oauth/authorize?client_id=f10b0afd5e2edbbd4ed8&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Foauth%2Fcallback&scope=read%3Aorg&state=AruY3s6MMcMS4K4bn2T2zBqG8dW9vDxq_OX6zTUqA_yfveX_mF5TJ7KeSQgSNko2WlXYnc2YjF7rihnbMkzjlq58FPJ77hTxXysoTZiJXDyg",
"login_uri": "/api/v1/oauth/login",
"state": "AruY3s6MMcMS4K4bn2T2zBqG8dW9vDxq_OX6zTUqA_yfveX_mF5TJ7KeSQgSNko2WlXYnc2YjF7rihnbMkzjlq58FPJ77hTxXysoTZiJXDyg",
"expiry": "2022-09-16T14:44:27.256613564+07:00"
}
}
}
The key fields in the response are the authorize_url
and the login_uri
. The authorize_url
must be
opened in a browser window and allows the user to authorize with their provider and grant the necessary
permissions to RPort so that it can obtain a provider access_token
for checking the user and
permitting access to access RPort. The login_uri
is the RPort API endpoint that allows an OAuth
authorization code
to be to be used to login to RPort and obtain an RPort JWT Bearer token. The state
value is
the same as the state
query param in the authorize_url
and is provided for developer convenience.
The expiry
value indicates when the state
value will expire, after which /auth/ext/settings
must be called again to obtain a new authorize_url
.
After the OAuth provider authorization has completed and after the user has been authenticated and they
have granted RPort permission to access their details stored with the OAuth provider, then the
OAuth provider server will redirect the browser back to the value configured via the redirect_uri
configuration parameter (see Configuration Settings). Included
as a query parameter in the redirect url will be an authorization code
value and the state
value
(from the authorize_url
). The authorization code
can be used to login to RPort to obtain an RPort JWT
Bearer token using the login_uri
provided above. It is STRONGLY recommended that developers check
that the value state
value included matches the state
value originally supplied in the
authorize_url
(see above). This will significantly reduce the chance of hackers potentially
obtaining RPort access via OAuth CSRF (see OAuth 2.0 Threat Model and Security Considerations) attacks.
Once an authorization code
has been obtained then it can be used to
login to RPort and obtain an RPort JWT Bearer token using the login_uri
included in the /auth/ext/settings
response. An example is provided below:
export LOGIN_URI="/api/v1/oauth/login"
export CODEANDSTATE="code=6611e4160148e7babced&state=AruY3s6MMcMS4K4bn2T2zBqG8dW9vDxq_OX6zTUqA_yfveX_mF5TJ7KeSQgSNko2WlXYnc2YjF7rihnbMkzjlq58FPJ77hTxXysoTZiJXDyg"
curl -s "http://localhost:3000$LOGIN_URI/?$CODEANDSTATE" | jq
This will return a response similar to the below:
{
"data": {
"token": "eyJhbGcIOIJIUZI1NiIsInR5DCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IMRpcy1yb2JpbnMiLCJzY22WZXMiOlt7InVyaSI6IioiLCJtZXRobnQiOiIqIn0seyJ1cmkiOiIvYXBpL3YxL3AlcmlmeS0yZmEiLCJtZXRob2QiOiIqIiwiZXhjbHVkZSI6DHJ1ZX1dLCJqdGkiOiIxMZc4MzMwMjkwNjK1NjgzNzizNSJ9.p6VZ8S_OWltL9lgGWP27UK-Y612R9f_ZrlUPwOS3sDA",
"two_fa": null
}
}
The token
field contains the RPort JWT Bearer token that can be used with subsequent RPort API calls.
To initiate the user sign-in when running an CLI or similar constrained app, the /auth/ext/settings/device
endpoint (as returned by the /auth/provider
endpoint) must be called.
curl -s "http://localhost:3000/api/v1/auth/ext/settings/device" | jq
This will return a response similar to the below:
{
"data": {
"auth_provider": "microsoft",
"details": {
"login_uri": "/oauth/login/device",
"auth_info": {
"user_code": "AN9T6DQEF",
"device_code": "SBQABAEEAAFD--DLA3Vf7QrddgJJ7Wevr_4FAnSQ6N2JKg9u2I2Qs9EZzbU9X7rnlmnsuwpT8ZwFM4YRVDZ4l9S_aE3DA-0jUAyQ7yEBE-hyMFcVaB9nfubMnkUgW-o5_ahaZ-XGGFeyRon0zOy_kJL_n0t7tp6EgwH-oIGB7vLU2nf7CVWdhn_XRGME_GhG532hXq9EmuV4gAA",
"verification_uri": "https://microsoft.com/devicelogin",
"expires_in": 900,
"interval": 5,
"message": "To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code SN9T8CSEF to authenticate."
}
}
}
}
The auth_provider
field repeats which OAuth provider is being used.
The login_uri
is the rportd
endpoint which should be polled to check if the user has authorized
yet.
The verification_uri
and user_code
must be displayed to the signing in user who must then separately
open a browser, visit the page indicated by the verification_uri
and enter the user_code
provided.
After which they will be asked to authorize the RPort access. Once the user has authorized succesfully
then calls to the login_uri
will return an ok status.
The interval
value indicates how long should be waited between authorization status checks via the
login_uri
.
The expires_in
field indicates when the user_code
provided will expire.
To complete the sign-in, the URL previously returned as the login_uri
must be polled to see if
the user has completed their authorization yet. The call must include the device_code
to
identity the device (and therefore user) making the authorization request. The response will
either be that the user has completed authorization, or that the authorization is still pending,
or that there has been an error. Given a device_code
, the login_uri
can be checked as shown in
the example below:
export DEVICE_CODE="e469c14g435103f8cd43bed2a633581f0be033b2"
curl -s "http://localhost:3000/api/v1/oauth/login/device?device_code=$DEVICE_CODE" | jq
If the user has authorized, this will return a response similar to the below:
{
"data": {
"token": "eyJhbGcioiJIUzj1NiIqInR5cCc6IkpXwCJ9.eyJ1c3VybmFTZSI6Im3vcmVzdcF0aWMwMF9nbWFpBC5jb20jRVhUI0Btb3Jlc3RhdGlJMDBnbWFpbC5vbm1pY3Jvc30mdC5jb20iLCJzY29wZXMiOlt7InVyasi6IioiLCJtZXRob2QiOiIqIN0seyJ1cmkiOiIvYXBpL3YxL3ZlcmlmeS0yZmEiLCJtZXRob2QiOiIqIiwiZXhjbHVkZSI6dHJ1ZX1dLCJqdGkiOiIxMzY4MzM3NTYzODUyOTY5NTI3NSJ9.JKM4OZ_I5XgboJq9huityvkf5kJRibV4rIev0P-QWLs",
"two_fa": null
}
}
The token
field contains the RPort JWT Bearer token that can be used with subsequent RPort API calls.
If the user’s authorization is still pending then a response similar to the below will be returned:
{
"data": {
"status_code": 200,
"error": "authorization_pending",
"error_description": "The authorization request is still pending.",
"error_uri": "https://docs.github.com/developers/apps/authorizing-oauth-apps#error-codes-for-the-device-flow"
}
}
If the user’s authorization status is checked before the interval
period has completed then further
requests will be rate limited and a slow_down
response similar to the below will be returned:
{
"data": {
"status_code": 200,
"error": "slow_down",
"error_description": "Too many requests have been made in the same timeframe.",
"error_uri": "https://docs.github.com"
}
}
If there’s an error then a response similar to the below will be returned:
{
"data": {
"status_code": 200,
"error": "incorrect_device_code",
"error_description": "The device_code provided is not valid.",
"error_uri": "https://docs.github.com/developers/apps/authorizing-oauth-apps#error-codes-for-the-device-flow"
}
}
Note that the OAuth providers are not consistent when returning http status codes. Therefore it is
best to always check the value of error
and when not empty handle the error accordingly. Only the
authorization_pending
and slow_down
error are soft errors which can be retries. All other errors
are hard and should be displayed to the user and the sign-in stopped.