Support for creating an App
and logging in to a server.
See https://docs.joinmastodon.org/client/authorized/
The result type of the loginTask
function.
It's either a task to fetch the logged-in user's Mastodon.Entity.Account
or a task to redirect to the authorization server to get a code.
The two String
s in FetchAccount
are the server name and token.
The String
in Redirect
is the server name.
loginTask : { client_name : String, server : String, applicationUri : String } -> Maybe String -> FetchAccountOrRedirect msg
Get a token and, if possible, the logged in Account
from the server.
The Maybe String
arg is a login token, called maybeToken
below, if
it is not Nothing.
Returns a Task
to either fetch an Account
for a known authorization token,
or to redirect to the authentication server to create a code with which
to mint the token.
If maybeToken
is not Nothing
, will attempt to get an Account
using that token. If that fails, will return an error. If maybeToken
is Nothing
, will create a new App
, and redirect to do
authentication. When the application is restarted, with a code
in
the URL query, call getTokenTask
to use that code and the saved
App
instance to mint a new token, and to use that to get an
Account
.
Usually, you will get a Token
from persistent
localStorage
, pass that here, and successfully receive the Account
back. No redirects necessary. But the redirects must happen at least
once, and then whenever the authorization token expires. This is step
8 below. Only if that fails will this do step 3, or, if there was no
persisted client id and secret, steps 1 through 3.
Currently, permission for all scopes is requested. Maybe the scopes should be passed as a parameter.
The full login procedure is as follows:
Send "POST /api/v1/apps" to the Mastodon server, via a PostApp
request,
Receive the returned App, including client_id
and client_secret
.
Save it in localStorage, keyed with the Mastodon server's host name
(from applicationUri
).
Redirect to <server_url>/oauth/authorize?client_id=<client_id>&redirect_uri=<applicationUri>&response_type=code&scope=<scopes>
The user enters login authorization information to the server web site.
The server web site redirects to <applicationUri>?code=<code>
Lookup the saved App
instance using the Mastodon server's host name
(which your top-level application must persist somewhere).
Use that to POST to <server_url>/oauth/token
:
POST /oauth/token HTTP/1.1
Host: <server_url>
Authorization: Basic `(Base64.encode (<client_id> ++ ":" ++ <client_secret>))`
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=<code>&redirect_uri=<applicationUri>&client_id=<client_id>&client_secret=<client_secret>
The Authorization
header isn't needed for new Mastodon API servers,
but that's how it was done for old ones, so I'm hoping this will give
some backward compatibility.
Receive back token information, JSON-encoded:
{ "access_token":"cptLSO8ff7zKbBXlTTyH15bnxQS5b9erVUWi_n0_EGd",
"token_type":"Bearer",
"scope":"write,read,follow,push",
"created_at":1561845912
}
Use the token_type
and access_token
to authenticate a request
for the user's Account
.
getTokenTask : { code : String, server : String, app : Mastodon.Entity.App } -> Task ( String, Mastodon.Request.Error ) ( String, Mastodon.Entity.Authorization, Mastodon.Entity.Account )
Continue after being restarted with a code
and state
in the URL query.
This continues from step 6 in the full login procedure description,
which is included with the documentation for loginTask
above.
Your application will usually persist the Authorization
, so you can use it
the next time the user starts the application, as a parameter to loginTask
.
The String
in the Task
is the server name, e.g. "mastodon.social".
appToAuthorizeUrl : String -> Mastodon.Entity.App -> String
Compute URL to redirect to for authentication.
Args are:
appToAuthorizeUrl server app
Returns:
https://<server>/oauth/authorize
?client_id=<app.client_id>
&redirect_uri=<app.redirect_uri>
&response_type=code
&scope=<all scopes>
You will call this explicitly only when a token expires, and you need
to mint a new one from a previously created App
:
appToAuthorizeUrl server app
|> Browser.Navigation.load