KindeClientSDK (kinde_sdk v1.0.0)

Kinde Client supporting client_credentials, authorization_code and pkce OAuth2 methods, providing authentication functionalities to your Kinde business.

configuration

Configuration

api-keys

API Keys

You can set your keys in your application configuration. Use config/config.exs. For example:

config :kinde_sdk,
  backend_client_id: "test_x1y2z3a1",
  frontend_client_id: "test_a1b2c3d4",
  client_secret: "test_112233",
  redirect_url: "http://text.com/callback",
  domain: "https://test.kinde.com",
  logout_redirect_url: "http://text.com/logout"

Optionally, you can also set scope as well.

config :kinde_sdk,
  scope: "email"

You can also use System.get_env/1 to retrieve the API key from an environment variables. For example:

config :kinde_sdk,

  backend_client_id: System.get_env("KINDE_BACKEND_CLIENT_ID")

usage

Usage

Initialize your client like this:

{conn, client} =
  KindeClientSDK.init(
    conn,
    Application.get_env(:kinde_sdk, :domain),
    Application.get_env(:kinde_sdk, :redirect_url),
    Application.get_env(:kinde_sdk, :backend_client_id),
    Application.get_env(:kinde_sdk, :client_secret),
    :client_credentials,
    Application.get_env(:kinde_sdk, :logout_redirect_url)
  )

conn will be phoenix connection here here. Now, you can use other implemented client functions, like login and get_token.

ets-cache

ETS Cache

KindeClientSDK implements persistant ETS cache for storing the client data and authenticating variables.

You may call your created client like this:

  client = KindeClientSDK.get_kinde_client(conn)

tokens

Tokens

We can use Kinde cache to get the tokens generated by login and get_token functions.

  KindeClientSDK.get_all_data(conn)

Link to this section Summary

Types

Options that may be passed to a request function. See request/2 for detailed descriptions.

Functions

Returns whether if a user is logged in by verifying that the access token is still valid.

The function allows you to create organization. Similar to register, the returing conn will redirect to the your Kinde business registration page.

Perform a DELETE request.

Perform a DELETE request.

Perform a GET request.

Perform a GET request.

Returns all the Kinde data (tokens) returned.

Returns the authentication status.

Returns the Kinde cache PID from the conn.

Returns a single claim from token and its value.

Returns token claims and their value.

Returns new grant type. Used by get_token function.

Returns the Kinde client created from the conn.

Returns the org code from the claims.

Given a permission value, returns if it is granted or not and relevant org code.

Returns an object with a list of permissions and also the relevant org code.

Fetches the tokens for your KindeClient. The tokens can be obtained through Kinde cache afterwards.

Returns the user details after successful authentication.

Returns the org code from the user token.

Perform a HEAD request.

Perform a HEAD request.

Used for initializing the Kinde client which will be then used other implemented client functions, like login and get_token.

Login function for KindeClient. If grant type is :client_credentials, then access token will be generated and stored to KindeCache. For other grant types, returned conn will redirect to the your Kinde business login page.

Log outs your client. Returned conn redirects to you to Kinde logout page and returns back to your logout redirect url.

Perform a OPTIONS request.

Perform a OPTIONS request.

Perform a PATCH request.

Perform a PATCH request.

Perform a POST request.

Perform a POST request.

Perform a PUT request.

Perform a PUT request.

Register function for your KindeClient. Returing conn will redirect to the your Kinde business registration page.

Perform request and raise in case of error.

Saves the Kinde client created into the conn.

Perform a TRACE request.

Perform a TRACE request.

Link to this section Types

@type option() ::
  {:method, Tesla.Env.method()}
  | {:url, Tesla.Env.url()}
  | {:query, Tesla.Env.query()}
  | {:headers, Tesla.Env.headers()}
  | {:body, Tesla.Env.body()}
  | {:opts, Tesla.Env.opts()}

Options that may be passed to a request function. See request/2 for detailed descriptions.

Link to this section Functions

Link to this function

authenticated?(conn)

@spec authenticated?(Plug.Conn.t()) :: boolean()

Returns whether if a user is logged in by verifying that the access token is still valid.

usage

Usage

  KindeClientSDK.authenticated?(conn)
Link to this function

create_org(conn, client, additional_params \\ %{})

@spec create_org(
  Plug.Conn.t(),
  %KindeClientSDK{
    additional_params: map(),
    auth_status: atom(),
    authorization_endpoint: <<_::64, _::_*8>>,
    cache_pid: pid(),
    client_id: any(),
    client_secret: any(),
    domain: binary(),
    grant_type: any(),
    logout_endpoint: <<_::56, _::_*8>>,
    logout_redirect_uri: any(),
    redirect_uri: binary(),
    scopes: any(),
    token_endpoint: <<_::64, _::_*8>>
  },
  map()
) :: Plug.Conn.t()

The function allows you to create organization. Similar to register, the returing conn will redirect to the your Kinde business registration page.

usage

Usage

  conn = KindeClientSDK.create_org(conn, client)

additional_params is an optional and defaults to %{}. It accepts :audience, :org_code and :org_name keys in the map with string as values.

Link to this function

delete(client, url, opts)

@spec delete(Tesla.Env.client(), Tesla.Env.url(), [option()]) :: Tesla.Env.result()

Perform a DELETE request.

See request/1 or request/2 for options definition.

delete("/users")
delete("/users", query: [scope: "admin"])
delete(client, "/users")
delete(client, "/users", query: [scope: "admin"])
delete(client, "/users", body: %{name: "Jon"})
Link to this function

delete!(client, url, opts)

@spec delete!(Tesla.Env.client(), Tesla.Env.url(), [option()]) ::
  Tesla.Env.t() | no_return()

Perform a DELETE request.

See request!/1 or request!/2 for options definition.

delete!("/users")
delete!("/users", query: [scope: "admin"])
delete!(client, "/users")
delete!(client, "/users", query: [scope: "admin"])
delete!(client, "/users", body: %{name: "Jon"})
Link to this function

get(client, url, opts)

Perform a GET request.

See request/1 or request/2 for options definition.

get("/users")
get("/users", query: [scope: "admin"])
get(client, "/users")
get(client, "/users", query: [scope: "admin"])
get(client, "/users", body: %{name: "Jon"})
Link to this function

get!(client, url, opts)

@spec get!(Tesla.Env.client(), Tesla.Env.url(), [option()]) ::
  Tesla.Env.t() | no_return()

Perform a GET request.

See request!/1 or request!/2 for options definition.

get!("/users")
get!("/users", query: [scope: "admin"])
get!(client, "/users")
get!(client, "/users", query: [scope: "admin"])
get!(client, "/users", body: %{name: "Jon"})
Link to this function

get_all_data(conn)

@spec get_all_data(Plug.Conn.t()) :: %{
  access_token: any(),
  expires_in: any(),
  id_token: any(),
  login_time_stamp: any(),
  token: any(),
  user: any(),
  oauth_code_verifier: any()
}

Returns all the Kinde data (tokens) returned.

usage

Usage

  data = KindeClientSDK.get_all_data(conn)
  IO.inspect(data.access_token, label: "Access Token")
Link to this function

get_auth_status(conn)

@spec get_auth_status(Plug.Conn.t()) :: any()

Returns the authentication status.

usage

Usage

  KindeClientSDK.get_auth_status(conn)
Link to this function

get_cache_pid(conn)

@spec get_cache_pid(Plug.Conn.t()) :: any()

Returns the Kinde cache PID from the conn.

usage

Usage

  pid = KindeClientSDK.get_cache_pid(conn)
Link to this function

get_claim(conn, key, token_type \\ :access_token)

@spec get_claim(Plug.Conn.t(), any(), any()) :: any()

Returns a single claim from token and its value.

usage

Usage

Third argument defaults to :access_token

  KindeClientSDK.get_claim(conn, "jti")

If used with :id_token

  KindeClientSDK.get_claim(conn, "jti", :id_token)
Link to this function

get_claims(conn, token_type \\ :access_token)

@spec get_claims(Plug.Conn.t(), any()) :: any()

Returns token claims and their value.

usage

Usage

Second argument defaults to :access_token

  KindeClientSDK.get_claims(conn)

If used with :id_token

  KindeClientSDK.get_claims(conn, :id_token)
Link to this function

get_grant_type(type)

@spec get_grant_type(
  :authorization_code
  | :authorization_code_flow_pkce
  | :client_credentials
) ::
  :authorization_code | :client_credentials

Returns new grant type. Used by get_token function.

Link to this function

get_kinde_client(conn)

@spec get_kinde_client(Plug.Conn.t()) :: %KindeClientSDK{
  additional_params: map(),
  auth_status: atom(),
  authorization_endpoint: <<_::64, _::_*8>>,
  cache_pid: pid(),
  client_id: any(),
  client_secret: any(),
  domain: binary(),
  grant_type: any(),
  logout_endpoint: <<_::56, _::_*8>>,
  logout_redirect_uri: any(),
  redirect_uri: binary(),
  scopes: any(),
  token_endpoint: <<_::64, _::_*8>>
}

Returns the Kinde client created from the conn.

usage

Usage

  client = KindeClientSDK.get_kinde_client(conn)
Link to this function

get_organization(conn)

@spec get_organization(Plug.Conn.t()) :: %{org_code: any()}

Returns the org code from the claims.

usage

Usage

  KindeClientSDK.get_user_organization(conn)
Link to this function

get_permission(conn, permission, token_type \\ :access_token)

@spec get_permission(Plug.Conn.t(), any(), any()) :: %{
  is_granted: boolean(),
  org_code: any()
}

Given a permission value, returns if it is granted or not and relevant org code.

usage

Usage

  KindeClientSDK.get_permission(conn, "create:users")
  KindeClientSDK.get_permission(conn, "create:users", :id_token)
Link to this function

get_permissions(conn, token_type \\ :access_token)

@spec get_permissions(Plug.Conn.t(), any()) :: %{org_code: any(), permissions: any()}

Returns an object with a list of permissions and also the relevant org code.

usage

Usage

  KindeClientSDK.get_permissions(conn)
  KindeClientSDK.get_permissions(conn, :id_token)
Link to this function

get_token(conn)

@spec get_token(Plug.Conn.t()) ::
  {Plug.Conn.t(),
   %KindeClientSDK{
     additional_params: map(),
     auth_status: atom(),
     authorization_endpoint: <<_::64, _::_*8>>,
     cache_pid: pid(),
     client_id: any(),
     client_secret: any(),
     domain: binary(),
     grant_type: any(),
     logout_endpoint: <<_::56, _::_*8>>,
     logout_redirect_uri: any(),
     redirect_uri: binary(),
     scopes: any(),
     token_endpoint: <<_::64, _::_*8>>
   }}

Fetches the tokens for your KindeClient. The tokens can be obtained through Kinde cache afterwards.

usage

Usage

  {conn, client} = KindeClientSDK.get_token(conn)

Get the tokens like this:

  pid = Conn.get_session(conn, :kinde_cache_pid)
  GenServer.call(pid, {:get_kinde_data, :kinde_access_token})
Link to this function

get_user_detail(conn)

@spec get_user_detail(Plug.Conn.t()) :: any()

Returns the user details after successful authentication.

usage

Usage

  KindeClientSDK.get_user_detail(conn)

Returns nil if not authenticated or if grant type is :client_credentials.

Link to this function

get_user_organizations(conn)

@spec get_user_organizations(Plug.Conn.t()) :: %{org_codes: any()}

Returns the org code from the user token.

usage

Usage

  KindeClientSDK.get_user_organizations(conn)
Link to this function

head(client, url, opts)

Perform a HEAD request.

See request/1 or request/2 for options definition.

head("/users")
head("/users", query: [scope: "admin"])
head(client, "/users")
head(client, "/users", query: [scope: "admin"])
head(client, "/users", body: %{name: "Jon"})
Link to this function

head!(client, url, opts)

@spec head!(Tesla.Env.client(), Tesla.Env.url(), [option()]) ::
  Tesla.Env.t() | no_return()

Perform a HEAD request.

See request!/1 or request!/2 for options definition.

head!("/users")
head!("/users", query: [scope: "admin"])
head!(client, "/users")
head!(client, "/users", query: [scope: "admin"])
head!(client, "/users", body: %{name: "Jon"})
Link to this function

init(conn, domain, redirect_uri, client_id, client_secret, grant_type, logout_redirect_uri, scopes \\ "openid profile email offline", additional_params \\ %{})

@spec init(
  Plug.Conn.t(),
  binary(),
  binary(),
  any(),
  any(),
  any(),
  any(),
  binary(),
  map()
) ::
  {Plug.Conn.t(),
   %KindeClientSDK{
     additional_params: map(),
     auth_status: :unauthenticated,
     authorization_endpoint: <<_::64, _::_*8>>,
     cache_pid: pid(),
     client_id: any(),
     client_secret: any(),
     domain: binary(),
     grant_type: any(),
     logout_endpoint: <<_::56, _::_*8>>,
     logout_redirect_uri: any(),
     redirect_uri: binary(),
     scopes: any(),
     token_endpoint: <<_::64, _::_*8>>
   }}

Used for initializing the Kinde client which will be then used other implemented client functions, like login and get_token.

Initialize your client like this:

{conn, client} =
  KindeClientSDK.init(
    conn,
    Application.get_env(:kinde_sdk, :domain),
    Application.get_env(:kinde_sdk, :redirect_url),
    Application.get_env(:kinde_sdk, :backend_client_id),
    Application.get_env(:kinde_sdk, :client_secret),
    :client_credentials,
    Application.get_env(:kinde_sdk, :logout_redirect_url)
  )

conn will be phoenix connection here here.

scopes is an optional and defaults to "openid profile email offline". Scopes can be defined as string.

additional_params is an optional and defaults to %{}. It accepts :audience, :org_code and :org_name keys in the map with string as values.

Throws for invalid domain, redirect_uri and additional_params.

Link to this function

login(conn, client, additional_params \\ %{})

@spec login(
  Plug.Conn.t(),
  %KindeClientSDK{
    additional_params: map(),
    auth_status: atom(),
    authorization_endpoint: <<_::64, _::_*8>>,
    cache_pid: pid(),
    client_id: any(),
    client_secret: any(),
    domain: binary(),
    grant_type: any(),
    logout_endpoint: <<_::56, _::_*8>>,
    logout_redirect_uri: any(),
    redirect_uri: binary(),
    scopes: any(),
    token_endpoint: <<_::64, _::_*8>>
  },
  map()
) :: any()

Login function for KindeClient. If grant type is :client_credentials, then access token will be generated and stored to KindeCache. For other grant types, returned conn will redirect to the your Kinde business login page.

Your callback function will call get_token function to get the authenticated user's token.

usage

Usage

  conn = KindeClientSDK.login(conn, client)

additional_params is an optional and defaults to %{}. It accepts :audience, :org_code and :org_name keys in the map with string as values.

Throws for invalid grant_type.

@spec logout(Plug.Conn.t()) :: Plug.Conn.t()

Log outs your client. Returned conn redirects to you to Kinde logout page and returns back to your logout redirect url.

usage

Usage

  conn = KindeClientSDK.logout(conn)
Link to this function

options(client, url, opts)

@spec options(Tesla.Env.client(), Tesla.Env.url(), [option()]) :: Tesla.Env.result()

Perform a OPTIONS request.

See request/1 or request/2 for options definition.

options("/users")
options("/users", query: [scope: "admin"])
options(client, "/users")
options(client, "/users", query: [scope: "admin"])
options(client, "/users", body: %{name: "Jon"})
Link to this function

options!(client, url, opts)

@spec options!(Tesla.Env.client(), Tesla.Env.url(), [option()]) ::
  Tesla.Env.t() | no_return()

Perform a OPTIONS request.

See request!/1 or request!/2 for options definition.

options!("/users")
options!("/users", query: [scope: "admin"])
options!(client, "/users")
options!(client, "/users", query: [scope: "admin"])
options!(client, "/users", body: %{name: "Jon"})
Link to this function

patch(client, url, body, opts)

Perform a PATCH request.

See request/1 or request/2 for options definition.

patch("/users", %{name: "Jon"})
patch("/users", %{name: "Jon"}, query: [scope: "admin"])
patch(client, "/users", %{name: "Jon"})
patch(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Link to this function

patch!(client, url, body, opts)

Perform a PATCH request.

See request!/1 or request!/2 for options definition.

patch!("/users", %{name: "Jon"})
patch!("/users", %{name: "Jon"}, query: [scope: "admin"])
patch!(client, "/users", %{name: "Jon"})
patch!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Link to this function

post(client, url, body, opts)

Perform a POST request.

See request/1 or request/2 for options definition.

post("/users", %{name: "Jon"})
post("/users", %{name: "Jon"}, query: [scope: "admin"])
post(client, "/users", %{name: "Jon"})
post(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Link to this function

post!(client, url, body, opts)

Perform a POST request.

See request!/1 or request!/2 for options definition.

post!("/users", %{name: "Jon"})
post!("/users", %{name: "Jon"}, query: [scope: "admin"])
post!(client, "/users", %{name: "Jon"})
post!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Link to this function

put(client, url, body, opts)

Perform a PUT request.

See request/1 or request/2 for options definition.

put("/users", %{name: "Jon"})
put("/users", %{name: "Jon"}, query: [scope: "admin"])
put(client, "/users", %{name: "Jon"})
put(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Link to this function

put!(client, url, body, opts)

Perform a PUT request.

See request!/1 or request!/2 for options definition.

put!("/users", %{name: "Jon"})
put!("/users", %{name: "Jon"}, query: [scope: "admin"])
put!(client, "/users", %{name: "Jon"})
put!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Link to this function

register(conn, client, additional_params \\ %{})

@spec register(
  Plug.Conn.t(),
  %KindeClientSDK{
    additional_params: map(),
    auth_status: atom(),
    authorization_endpoint: <<_::64, _::_*8>>,
    cache_pid: pid(),
    client_id: any(),
    client_secret: any(),
    domain: binary(),
    grant_type: any(),
    logout_endpoint: <<_::56, _::_*8>>,
    logout_redirect_uri: any(),
    redirect_uri: binary(),
    scopes: any(),
    token_endpoint: <<_::64, _::_*8>>
  },
  map()
) :: Plug.Conn.t()

Register function for your KindeClient. Returing conn will redirect to the your Kinde business registration page.

usage

Usage

  conn = KindeClientSDK.register(conn, client)

additional_params is an optional and defaults to %{}. It accepts :audience, :org_code and :org_name keys in the map with string as values.

Link to this function

request(client \\ %Tesla.Client{}, options)

@spec request(Tesla.Env.client(), [option()]) :: Tesla.Env.result()

Perform a request.

options

Options

  • :method - the request method, one of [:head, :get, :delete, :trace, :options, :post, :put, :patch]
  • :url - either full url e.g. "http://example.com/some/path" or just "/some/path" if using Tesla.Middleware.BaseUrl
  • :query - a keyword list of query params, e.g. [page: 1, per_page: 100]
  • :headers - a keyworld list of headers, e.g. [{"content-type", "text/plain"}]
  • :body - depends on used middleware:
    • by default it can be a binary
    • if using e.g. JSON encoding middleware it can be a nested map
    • if adapter supports it it can be a Stream with any of the above
  • :opts - custom, per-request middleware or adapter options

examples

Examples

ExampleApi.request(method: :get, url: "/users/path")

# use shortcut methods
ExampleApi.get("/users/1")
ExampleApi.post(client, "/users", %{name: "Jon"})
Link to this function

request!(client \\ %Tesla.Client{}, options)

@spec request!(Tesla.Env.client(), [option()]) :: Tesla.Env.t() | no_return()

Perform request and raise in case of error.

This is similar to request/2 behaviour from Tesla 0.x

See request/2 for list of available options.

Link to this function

save_kinde_client(conn, client)

@spec save_kinde_client(Plug.Conn.t(), any()) :: :ok

Saves the Kinde client created into the conn.

usage

Usage

  KindeClientSDK.save_kinde_client(conn)
Link to this function

trace(client, url, opts)

Perform a TRACE request.

See request/1 or request/2 for options definition.

trace("/users")
trace("/users", query: [scope: "admin"])
trace(client, "/users")
trace(client, "/users", query: [scope: "admin"])
trace(client, "/users", body: %{name: "Jon"})
Link to this function

trace!(client, url, opts)

@spec trace!(Tesla.Env.client(), Tesla.Env.url(), [option()]) ::
  Tesla.Env.t() | no_return()

Perform a TRACE request.

See request!/1 or request!/2 for options definition.

trace!("/users")
trace!("/users", query: [scope: "admin"])
trace!(client, "/users")
trace!(client, "/users", query: [scope: "admin"])
trace!(client, "/users", body: %{name: "Jon"})