Ueberauth.Strategy.IntervalsIcu (Ueberauth intervals.icu v0.1.0)

Copy Markdown View Source

Ueberauth strategy for authenticating athletes with intervals.icu.

Setup

Register an application at https://intervals.icu/settings to obtain a client id and secret, and register your exact callback URL. intervals.icu does not support wildcards in redirect URIs. Every callback URL must be registered in full.

Add the provider to your Ueberauth configuration:

config :ueberauth, Ueberauth,
  providers: [
    intervals_icu: {Ueberauth.Strategy.IntervalsIcu, [default_scope: "ACTIVITY:READ"]}
  ]

config :ueberauth, Ueberauth.Strategy.IntervalsIcu.OAuth,
  client_id: System.get_env("INTERVALS_ICU_CLIENT_ID"),
  client_secret: System.get_env("INTERVALS_ICU_CLIENT_SECRET")

Options

  • :default_scope - scopes requested when the request phase does not receive a scope query parameter. Defaults to "ACTIVITY:READ,WELLNESS:READ".

  • :fetch_athlete - whether to call the athlete endpoint after the token exchange to build a fuller Ueberauth.Auth.Info. Defaults to true. See "Fetching the athlete" below.

  • :userinfo_endpoint - the endpoint used when :fetch_athlete is true. Defaults to "/api/v1/athlete/0". The athlete id 0 always means "the athlete this token belongs to".

  • :uid_field - which athlete field becomes Ueberauth.Auth.uid. Defaults to :id.

  • :oauth2_module - the module implementing the OAuth calls. Defaults to Ueberauth.Strategy.IntervalsIcu.OAuth.

Scopes

intervals.icu scopes are ACTIVITY, WELLNESS, CALENDAR, CHATS, LIBRARY and SETTINGS, each suffixed with :READ or :WRITE, and joined with commas rather than the spaces used by most OAuth 2.0 providers:

default_scope: "ACTIVITY:READ,WELLNESS:WRITE"

Fetching the athlete

The token response already contains the athlete's id and name, so this strategy can identify the athlete without any further request.

By default it still calls :userinfo_endpoint to populate a richer Ueberauth.Auth.Info, mirroring how most Ueberauth strategies behave. That endpoint may require a scope your application did not request, in which case intervals.icu answers 403 and authentication fails.

If that happens, either request the necessary scope or turn the call off:

providers: [
  intervals_icu: {Ueberauth.Strategy.IntervalsIcu, [fetch_athlete: false]}
]

With fetch_athlete: false no extra request is made and the auth struct is built from the athlete map inside the token response. You get uid and name, but not email or the other profile fields.

Tokens do not expire, and there are no refresh tokens

intervals.icu issues no refresh token and no expiry, so Ueberauth.Auth.Credentials always comes back with refresh_token: nil, expires: false and expires_at: nil. Store the access token and use it until it stops working; to recover, send the athlete through the flow again.

A token can be revoked with:

DELETE https://intervals.icu/api/v1/disconnect-app
Authorization: Bearer <token>

Summary

Functions

The token, its type and its granted scopes.

The raw token and athlete payloads, for anything this strategy does not map.

Handles the redirect back from intervals.icu.

Removes the data this strategy stored on the connection.

Redirects the athlete to the intervals.icu authorize endpoint.

The athlete's profile information.

The athlete's unique id, taken from the field named by :uid_field.

Functions

credentials(conn)

The token, its type and its granted scopes.

refresh_token, expires and expires_at are always nil/false, because intervals.icu issues neither refresh tokens nor expiring access tokens.

default_options()

Callback implementation for Ueberauth.Strategy.default_options/0.

extra(conn)

The raw token and athlete payloads, for anything this strategy does not map.

handle_callback!(conn)

Handles the redirect back from intervals.icu.

On success the token is exchanged and, unless :fetch_athlete is disabled, the athlete is fetched. A denial arrives as ?error=access_denied.

handle_cleanup!(conn)

Removes the data this strategy stored on the connection.

handle_request!(conn)

Redirects the athlete to the intervals.icu authorize endpoint.

A scope query parameter on the request overrides :default_scope, letting a single provider ask for different scopes per request.

info(conn)

The athlete's profile information.

Only :name is guaranteed, because it is present in the token response. The remaining fields depend on what the athlete endpoint returns and are nil when absent. The complete, untouched athlete map is always available via extra/1.

uid(conn)

The athlete's unique id, taken from the field named by :uid_field.