Created
November 2, 2018 23:58
-
-
Save mscharley/c82180cb4afa9fd2b94e460ed2f6fe01 to your computer and use it in GitHub Desktop.
Sample Session handler for bs-auth0-js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open Belt.Option; | |
open Js.Nullable; | |
open BsQuerystringify.QueryStringify; | |
open BsAuth0Js; | |
type accessToken = string; | |
type id = { | |
email: option(string), | |
name: option(string), | |
picture: option(string), | |
userId: string, | |
} | |
and loginEvent = { | |
accessToken, | |
id, | |
session: t, | |
returnUrl: option(string), | |
} | |
and errorEvent = { | |
error: string, | |
errorDescription: string, | |
} | |
and options = { | |
auth: WebAuth.t, | |
origin: string, | |
onLogin: loginHandler, | |
onRenew: loginHandler, | |
onError: errorHandler, | |
} | |
and loginHandler = loginEvent => unit | |
and errorHandler = errorEvent => unit | |
and t = | |
| Pending(options) | |
| LoggedOut(options) | |
| Session(options, string, id); | |
let create = | |
( | |
~domain, | |
~clientId, | |
~origin, | |
~scope="openid profile email", | |
~onLogin=_ => (), | |
~onRenew=_ => (), | |
~onError=_ => (), | |
(), | |
) => { | |
let auth = | |
WebAuth.createWebAuth( | |
WebAuth.createOptions( | |
~domain, | |
~clientID=clientId, | |
~responseType="token id_token", | |
~scope, | |
(), | |
), | |
); | |
Pending({auth, origin, onLogin, onRenew, onError}); | |
}; | |
let idFromWebauthPayload = payload => { | |
userId: payload->WebAuth.subGet, | |
email: payload->WebAuth.emailGet, | |
name: payload->WebAuth.nameGet, | |
picture: payload->WebAuth.pictureGet, | |
}; | |
let isLoggedIn = s => | |
switch (s) { | |
| Session(_, _, _) => true | |
| _ => false | |
}; | |
let isPending = s => | |
switch (s) { | |
| Pending(_) => true | |
| _ => false | |
}; | |
let updateState = (s, update) => | |
switch (s) { | |
| Pending(state) => Pending(state->update) | |
| LoggedOut(state) => LoggedOut(state->update) | |
| Session(state, accessToken, id) => | |
Session(state->update, accessToken, id) | |
}; | |
let onLogin = (s, handler) => | |
s->updateState(state => {...state, onLogin: handler}); | |
let onRenew = (s, handler) => | |
s->updateState(state => {...state, onRenew: handler}); | |
let onError = (s, handler) => | |
s->updateState(state => {...state, onError: handler}); | |
let rec handleAuthResult = (state, success, err, result) => | |
switch (err->toOption, result->toOption) { | |
| (None, None) => | |
state.onError({ | |
error: "missing_token", | |
errorDescription: "There was an error with the authentication server.", | |
}) | |
| (Some(e), _) => | |
state.onError({ | |
error: e->WebAuth.errorGet, | |
errorDescription: e->WebAuth.errorDescriptionGet, | |
}) | |
| (_, Some(result)) => | |
switch (result->WebAuth.accessTokenGet, result->WebAuth.idTokenPayloadGet) { | |
| (None, _) | |
| (_, None) => | |
state.onError({ | |
error: "missing_token", | |
errorDescription: "There was an error with the authentication server.", | |
}) | |
| (Some(accessToken), Some(idToken)) => | |
let id = idToken->idFromWebauthPayload; | |
let search = parseQueryString(Util.locationSearch); | |
let event = { | |
accessToken, | |
id, | |
session: Session(state, accessToken, id), | |
returnUrl: search->Js.Dict.get("return"), | |
}; | |
let expiryMs = (result->WebAuth.expiresInGet->int_of_float - 120) * 1000; | |
Js.log2("Setting up token refresh timeout for", expiryMs); | |
Js.Global.setTimeout(() => event.session->doRenew, expiryMs) |> ignore; | |
success(event); | |
} | |
} | |
and doRenew = s => | |
switch (s) { | |
| Pending(state) | |
| LoggedOut(state) => | |
state.auth | |
->WebAuth.renewAuthWithOptions( | |
WebAuth.renewOptions( | |
~redirectUri=state.origin ++ "/oauth/callback?renew=true", | |
(), | |
), | |
state->handleAuthResult(state.onLogin), | |
) | |
| Session(state, _, _) => | |
state.auth | |
->WebAuth.renewAuthWithOptions( | |
WebAuth.renewOptions( | |
~redirectUri=state.origin ++ "/oauth/callback?renew=true", | |
(), | |
), | |
state->handleAuthResult(state.onRenew), | |
) | |
}; | |
let doLogin = (s, ~returnUrl=?, ()) => | |
switch (s) { | |
| Pending(state) | |
| LoggedOut(state) => | |
state.auth | |
->WebAuth.authorizeWithOptions( | |
WebAuth.authorizeOptions( | |
~redirectUri= | |
state.origin | |
++ "/oauth/callback" | |
++ returnUrl->map(s => "?return=" ++ s)->getWithDefault(""), | |
(), | |
), | |
) | |
| Session(_, _, _) => () | |
}; | |
let doLogout = | |
fun | |
| Session({auth, origin}, _, _) => | |
auth->WebAuth.logoutWithOptions( | |
WebAuth.logoutOptions(~returnTo=origin ++ "/", ()), | |
) | |
| Pending(_) | |
| LoggedOut(_) => (); | |
let doLocalLogout = | |
fun | |
| Session(state, _, _) | |
| Pending(state) | |
| LoggedOut(state) => LoggedOut(state); | |
let doCallback = | |
fun | |
| Session(state, _, _) => | |
state.auth->WebAuth.parseHash(handleAuthResult(state, state.onRenew)) | |
| Pending(state) | |
| LoggedOut(state) => | |
state.auth->WebAuth.parseHash(handleAuthResult(state, state.onLogin)); | |
let accessTokenGet = | |
fun | |
| Session(_, accessToken, _) => Some(accessToken) | |
| _ => None; | |
let idGet = | |
fun | |
| Session(_, _, id) => Some(id) | |
| _ => None; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type t; | |
type accessToken; | |
type id = { | |
email: option(string), | |
name: option(string), | |
picture: option(string), | |
userId: string, | |
}; | |
type loginEvent = { | |
accessToken, | |
id, | |
session: t, | |
returnUrl: option(string), | |
}; | |
type errorEvent = { | |
error: string, | |
errorDescription: string, | |
}; | |
type loginHandler = loginEvent => unit; | |
type errorHandler = errorEvent => unit; | |
let create: | |
( | |
~domain: string, | |
~clientId: string, | |
~origin: string, | |
~scope: string=?, | |
~onLogin: loginHandler=?, | |
~onRenew: loginHandler=?, | |
~onError: errorHandler=?, | |
unit | |
) => | |
t; | |
let isLoggedIn: t => bool; | |
let isPending: t => bool; | |
let onLogin: (t, loginHandler) => t; | |
let onRenew: (t, loginHandler) => t; | |
let onError: (t, errorHandler) => t; | |
let doLogin: (t, ~returnUrl: string=?, unit) => unit; | |
let doRenew: t => unit; | |
let doLogout: t => unit; | |
let doLocalLogout: t => t; | |
let doCallback: t => unit; | |
let accessTokenGet: t => option(accessToken); | |
let idGet: t => option(id); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment