This package helps you make XSRF protected HTTP requests.
This package was designed to be used with servant-auth. However it should be compatible with any backend that supports cookie based XSRF authentication.
You can find a complete example of an elm app and a servant-auth backend using XSRF tokens here.
In order to get the cookies that the server has set, you need to ask javascript for it. The simplest way is to get hold off the document object and pass it through a flag to Elm as a JSON Value.
// you would normally put this in a <script> tag inside your app's
// index.html file
let app = Elm.App.init(
{ node: document.getElementById("myapp")
// Pass the document object as a flag
, flags: document
}
);
In Elm , you'll need to retrieve the document JSON Value sent by javascript.
import Json.Decode as D
-- main parametrised to D.Value to recieve the document object
main : Program D.Value Model Msg
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
-- Initialize the elm runtime with the document object
init : D.Value -> ( Model, Cmd Msg )
init document =
( initModel document
, initCmd
)
type alias Model =
{ document : D.Value }
initModel : D.Value -> Model
initModel document =
Model document
Now that you have all current cookies in your elm app, you should check if one of them is a valid XSRF one.
token : String -> Json.Decode.Value -> Maybe String
Get an XSRF token from a document json object. The first argument is name the server used to set the XSRF cookie e.g. "XSRF-TOKEN="
token "XSRF-TOKEN=" model.document
get : { url : String, expect : Http.Expect msg, xsrfHeaderName : String, xsrfToken : Maybe String } -> Platform.Cmd.Cmd msg
Similar to Http.get, but you also need to provide a XSRF header name and token.
-- A protected request for an email address
getEmailRequest : Model -> Cmd Msg
getEmailRequest model =
XSRF.get
{ url = "http://localhost:4000/email"
, expect = Http.expectJson ReceivedEmail D.string
, xsrfHeaderName = "X-XSRF-TOKEN"
, xsrfToken = XSRF.token "XSRF-TOKEN=" model.document
}
post : { url : String, body : Http.Body, expect : Http.Expect msg, xsrfHeaderName : String, xsrfToken : Maybe String } -> Platform.Cmd.Cmd msg
Similar to Http.post, but you also need to provide a XSRF header name and token.
put : { url : String, body : Http.Body, expect : Http.Expect msg, xsrfHeaderName : String, xsrfToken : Maybe String } -> Platform.Cmd.Cmd msg
Create a XSRF-protected PUT request.
request : { method : String, headers : List Http.Header, url : String, body : Http.Body, expect : Http.Expect msg, xsrfHeaderName : String, xsrfToken : Maybe String, timeout : Maybe Basics.Float, tracker : Maybe String } -> Platform.Cmd.Cmd msg
Similar to Http.request, but you also need to provide a XSRF header name and token.
In case you don't want to provide any other header except the XSRF one, you can apply the empty list in the headers argument
-- saves a blog post
putPost : D.Value -> String -> Cmd msg
putPost document post =
XSRF.request
{ method = "PUT"
, headers = []
, url = "http://localhost:4000/savePost"
, body = Http.jsonBody <| E.string post
, expect = Http.expectWhatever
, xsrfHeaderName = "XSRF-CUSTOM"
, xserfToken = XSRF.token "XSRF-COOKIE=" document
, timeout = Nothing
, tracker = Nothing
}