Zaid-Ajaj / Fable.Remoting

Type-safe communication layer (RPC-style) for F# featuring Fable and .NET Apps
https://zaid-ajaj.github.io/Fable.Remoting/
MIT License
272 stars 54 forks source link

Documentation for integrating different authentication and authorization techniques #229

Open Zaid-Ajaj opened 3 years ago

Zaid-Ajaj commented 3 years ago

Based on feedback from users, it can be really tricky to secure a remoting API, whether that deals with an internal security system or one that integrates a third-party into the mix such as Azure active directory or Auth0.

Currently the documentation only scratches the surface where you can see that you the remoting building has access to the HttpContext which in turn has access to the context of the currently authorized user or other security services injected by means of DI. Still, the issue remains of how to go from this to a full integration along with handling authentication on the client side as well

I would like to compile a series of guides into the documentation website for integrating these 3rd party systems and what things there are to consider.

Help needed from people who actively have worked and implemented some of the integrations or built their own layer on top.

kerams commented 3 years ago

I'm rolling my own dead simple, cookie-based, internal system.

I have an auth Remoting handler with a login method that takes credentials as input and sets the session cookies if authentication succeeds. Then each Remoting method that needs to be secured uses a higher order function that checks the validation. It looks something like this:

// I use this return type for every method
type Response<'a> =
    | Unauthenticated
    | Unauthorized
    | OldVersion of 'a option
    | Fine of 'a

let requireAuthentication (ctx: HttpContext) (handler: _ -> _ -> Async<_>) = async {
    // authOk extracts cookies from the context, validates the session,
    // and passes the corresponding user into the handler if successful
    match! authOk ctx with
    | Some user -> return! handler request user
    | _ ->
        CookieAuth.deleteAuthCookies ctx.Response
        return Unauthenticated })

type AdministrationApi = {
    removeAttribute: Request<AttributeDefinitionId> -> Async<Response<Result<unit, unit>>>
}

let administrationApi (ctx: HttpContext) = {
    removeAttribute = requireAuthentication ctx (fun req user -> async {
        let! res = CompositionRoot.setAttributeDefinitionDeleted req true
        return Fine res
    })
}

Because this system is cookie-based, the browser takes care of cookie sending on every request as well as invalidation. The only thing the client needs to do is login (obviously) and handling the return types.

JamesRandall commented 3 years ago

I've integrated it with Saturn and "raw" ASP.Net Core both with a Fable client. I've got an end of March deadline but once that's clear happy to have a go at some write ups.

Dzoukr commented 3 years ago

I can provide examples of: Fable.Remoting on Frontend Fable.Remoting on Backend (using Giraffe) ASP.NET auth using JWT token (custom generated)

Is that what you would appreciate?

Dzoukr commented 3 years ago

@Zaid-Ajaj Can I pull request to (newly created) "Examples" folder? Or how do you want to have it?

Zaid-Ajaj commented 3 years ago

@kerams This is a great example of a simple implementation. I think it is the same of what @Dzoukr is suggesting?

@JamesRandall That would be super awesome! Many people are using Saturn ootb so an example integration is certainly more than welcome. No hurry of course

As for the actual guides, I am really hoping for guides that walk people through the different criteria and choices:

This is of course the ideal situation, you don't have to every small detail. I will help you extend what you come up with 😄 just keep in mind that the docs are targeted at beginners

Contributing is a matter of adding a new markdown file in ./{repo}/documentation/src/{your-auth-implementation}.md` and I will handle the rest. You can run the the documentation website locally as follows

cd documentation
npm install 
npm start

This should start the gitbook in localhost

I am here for any question, thanks a lot for helping out ❤️

Dzoukr commented 3 years ago

@Zaid-Ajaj would you like some more advanced example with sending errors as HTTP 4xx errors, custom Fable.Remoting error handler, using local storage for tokens, etc... ?

Zaid-Ajaj commented 3 years ago

@Dzoukr The more docs, the better IMO so it is really up to you 😉

absolutejam commented 3 years ago

I'm weirdly excited about this 😄

I've been implementing JWT auth in Saturn with Fable Remoting and it's been a big learning curve, but I think I now have it in a good place... However, I'm going to wait and see what comes from this before I settle on that opinion or release any code 😅

zelenij commented 3 years ago

I'm weirdly excited about this smile

I've been implementing JWT auth in Saturn with Fable Remoting and it's been a big learning curve, but I think I now have it in a good place... However, I'm going to wait and see what comes from this before I settle on that opinion or release any code sweat_smile

This example seems like a great starting point, but I don't think it would compile in real life. At least there is an inconsistency in onSecuredAPI usage, as it seems to me. Maybe a better option is to create a self contained sample project?

teknikal-wizard commented 3 years ago

I have two blogs up where I integrate AD with a SAFE app if they are any use https://www.compositional-it.com/news-blog/tag/safe-ad-auth/

Edit - I should say that I am just updating an app to SAFE V3 / .NET 5 and things didn't quite work the same so I will update those blogs once I have sussed it!