Packages

A thin RingCentral API Wrapper in Elixir

Current section

Files

Jump to
ringcentral lib ring_central oauth.ex
Raw

lib/ring_central/oauth.ex

defmodule RingCentral.OAuth do
@moduledoc """
The main module for the [Authorization flow](https://developers.ringcentral.com/api-reference/authentication)
"""
alias RingCentral.HTTPClient
alias RingCentral.Response
alias RingCentral.Error
@doc """
Get the URL for initializing the OAuth 2.0 authorizaiton flow.
`params` is a map contains the options described in
the [official documentation](https://developers.ringcentral.com/api-reference/Authorization)
## Example
```elixir
ringcentral = %RingCentral{
client_id: "the-client-id",
client_secret: "the-client-secret",
http_client: RingCentral.HTTPClient.DefaultClient,
server_url: "https://platform.ringcentral.com",
token_info: nil
}
{:ok, authorization_url} = RingCentral.OAuth.authorize(ringcentral, %{
response_type: "code",
redirect_uri: "https://ringcentral-elixir.test"
})
# {:ok, "https://service.ringcentral.com/..."}
```
"""
@spec authorize(RingCentral.t(), map()) :: {:error, RingCentral.Error.t()} | {:ok, String.t()}
def authorize(%RingCentral{} = ringcentral, params \\ %{}) do
query =
Map.merge(
%{
client_id: ringcentral.client_id
},
params
)
url =
ringcentral
|> build_url("/restapi/oauth/authorize")
|> Map.put(:query, URI.encode_query(query))
with {:ok, %Response{status: 302, headers: headers}} <-
HTTPClient.perform_request(ringcentral, :get, url, nil) do
location =
headers
|> Enum.reduce_while(nil, fn
{"location", v}, _acc -> {:halt, v}
_, acc -> {:cont, acc}
end)
{:ok, location}
else
error -> handle_error(error)
end
end
@doc """
Get the access token and refresh token.
`params` is a map contains the options described in
the [official documentation](https://developers.ringcentral.com/api-reference/Get-Token)
## Example
```elixir
ringcentral = %RingCentral{
client_id: "the-client-id",
client_secret: "the-client-secret",
http_client: RingCentral.HTTPClient.DefaultClient,
server_url: "https://platform.ringcentral.com",
token_info: nil
}
{:ok, token_info} = RingCentral.OAuth.get_token(ringcentral, %{
grant_type: "authorization_code",
code: "U0pDMDFQMDRQQVMwMnxBQUFGTVUyYURGYi0wUEhEZ2VLeGFiamFvZlNMQlZ5TExBUHBlZVpTSVlhWk",
redirect_uri: "https://ringcentral-elixir.test"
})
# {:ok, %{"access_token": "...", "token_type": "bearer", "refresh_token": "..."}}
```
"""
@spec get_token(RingCentral.t(), map()) :: {:error, RingCentral.Error.t()} | {:ok, map()}
def get_token(%RingCentral{} = ringcentral, params \\ %{}) do
url =
ringcentral
|> build_url("/restapi/oauth/token")
headers = [
{"Accept", "application/json"},
{"Content-Type", "application/x-www-form-urlencoded"},
{"Authorization",
"Basic " <> Base.encode64("#{ringcentral.client_id}:#{ringcentral.client_secret}")}
]
with {:ok, %Response{status: 200, body: body}} <-
HTTPClient.perform_request(
ringcentral,
:post,
url,
{:form, params},
headers
) do
token_info = RingCentral.JSON.decode!(ringcentral, body)
{:ok, token_info}
else
error -> handle_error(ringcentral, error)
end
end
@doc """
Revokes access/refresh token.
`token` is the active access or refresh token to be revoked,
see the [official documentation](https://developers.ringcentral.com/api-reference/Revoke-Token) for more information.
## Example
```elixir
ringcentral = %RingCentral{
client_id: "the-client-id",
client_secret: "the-client-secret",
http_client: RingCentral.HTTPClient.DefaultClient,
server_url: "https://platform.ringcentral.com",
token_info: nil
}
RingCentral.OAuth.revoke_token(ringcentral, "U0pDMDFQMDFKV1MwMXwJ_W7L1fG4eGXBW9Pp-otywzriCw")
# :ok
```
"""
@spec revoke_token(RingCentral.t(), String.t()) :: {:error, RingCentral.Error.t()} | :ok
def revoke_token(%RingCentral{} = ringcentral, token) do
url =
ringcentral
|> build_url("/restapi/oauth/revoke")
headers = [
{"Accept", "application/json"},
{"Content-Type", "application/x-www-form-urlencoded"},
{"Authorization",
"Basic " <> Base.encode64("#{ringcentral.client_id}:#{ringcentral.client_secret}")}
]
request_body = %{
token: token
}
with {:ok, %Response{status: 200}} <-
HTTPClient.perform_request(
ringcentral,
:post,
url,
{:form, request_body},
headers
) do
:ok
else
error -> handle_error(ringcentral, error)
end
end
defp handle_error(
ringcentral,
{:ok, %Response{status: status_code, body: body, headers: headers}}
)
when status_code >= 400 and status_code < 500 do
error_info = RingCentral.JSON.decode!(ringcentral, body)
{:error,
%Error{
code: :client_error,
detail: %{
status: status_code,
data: error_info,
headers: headers
}
}}
end
defp handle_error(
ringcentral,
{:ok, %Response{status: status_code, body: body, headers: headers}}
)
when status_code >= 500 do
error_info = RingCentral.JSON.decode!(ringcentral, body)
{:error,
%Error{
code: :server_error,
detail: %{
status: status_code,
data: error_info,
headers: headers
}
}}
end
defp handle_error({:error, %Error{} = err}) do
{:error, err}
end
defp build_url(%RingCentral{} = client, path) do
URI.merge(client.server_url, path)
end
end