Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create multiple sessions with supabase csharp #7

Closed
rubenvclceeic opened this issue Aug 23, 2021 · 9 comments
Closed

Create multiple sessions with supabase csharp #7

rubenvclceeic opened this issue Aug 23, 2021 · 9 comments
Labels
enhancement New feature or request

Comments

@rubenvclceeic
Copy link

Feature request

Create Mutiple acces to supebase

Is your feature request related to a problem? Please describe.

At the moment supebase csharp is a singelton class, so when you working on a web application net core, all acces a supebase are using the supebase class and the login is overlapping.
A clear and concise description of what you want and what your use case is.

Describe the solution you'd like

The solution is build supebase chsarp like a service(transient ).
A clear and concise description of what you want to happen.
One user call a supabase, the object have to be a unique object wiht the properties of this user.
At the moment if other user make a call, the supebase object mantain the last login user properties. So the correct way is create new object supebase to maintain the properties by user.

Describe alternatives you've considered

A clear and concise description of any alternative solutions or features you've considered.

Additional context

Add any other context or screenshots about the feature request here.

@rubenvclceeic rubenvclceeic added the enhancement New feature or request label Aug 23, 2021
@acupofjose
Copy link
Collaborator

@rubenvclceeic thanks for the request!

The library was structured after the way that Google's Firebase libraries are structured - all of their Xamarin bindings use a singleton pattern.

To clarify - you would want multiple users to be logged in at the same time without logging out in between them?

If that's correct, I'd say that I don't believe you can currently do that with any of the client libraries or with Firebase. If you can find an example otherwise, I'd very much like to see it!

@rubenvclceeic
Copy link
Author

rubenvclceeic commented Aug 24, 2021

Thank you for the answer. At the moment, I'm rewrite part of the librery to make Postgrest, Gotrue, and client Supabase.

But I don't have many time. If I have some importan progress I will let you know. ;-)

@evanrobertson
Copy link

@acupofjose This makes sense when you are doing something where you are contextually only ever working with 1 user account per instance of the client.

However when the application is a website or api built on ASP it would make sense for the JWT to be passed from the client to the application and the supabase client be able to make requests with that for the current request pipeline.

@acupofjose
Copy link
Collaborator

acupofjose commented Nov 22, 2021

@evanrobertson I see!

So in the end something like:

var token = "123456abcdefghijkplmnop";
// Would return a `Supabase.Client`
var instance = await Supabase.Client.FromAuthToken(url, key, token);

// Do API Calls making sub-clients using token
await instance.From<User>().Single();
await instance.Storage().From("testing").GetPublicUrl("i-am-a-test.png");

Would that work?

@evanrobertson
Copy link

I think something along those lines could make sense.

My preference would be that we could inject the client via dependency injection and then configure it per request (scoped).

I also can't see a method of validating the JWT easily, similar to what is described here: supabase/supabase#491 (comment)

@acupofjose
Copy link
Collaborator

@evanrobertson I'm going to start working on a StatelessClient to maintain backwards compatibility with current users but to expand this direction - I'll post some updates here when I've got some!

acupofjose added a commit to supabase-community/gotrue-csharp that referenced this issue Nov 24, 2021
@acupofjose acupofjose changed the title Create multiple sessions with supabase chsarp Create multiple sessions with supabase csharp Nov 26, 2021
acupofjose added a commit to supabase-community/postgrest-csharp that referenced this issue Nov 26, 2021
acupofjose added a commit that referenced this issue Nov 26, 2021
@acupofjose
Copy link
Collaborator

@evanrobertson

So what I have now you should be able to do the following:

With REST API:

using static Supabase.StatelessClient;
//...

var url = "https://1234abcd.supabase.io";
var applicationKey = "1234";
var options =  new Supabase.SupabaseOptions
{
  Headers = new Dictionary<string, string> {
    { "Authorization", "Bearer my-super-secret-user-token" }
  }
};

var result = await From<MODEL>(url, applicationKey, options).Get();
var items = result.Models
// .. blah blah blah

With GOTRUE API:

using static Supabase.StatelessClient;

var url = "https://1234abcd.supabase.io";
var applicationKey = "1234";

// Forms the appropriate `StatelessClientOptions`
var options = GetAuthOptions(url, applicationKey, options);

var user = await Supabase.Gotrue.StatelessClient.GetApi(options).GetUser("my-user-jwt");
// .. blah blah blah

You can find these changes on master - would you provide me some feedback on them?

Thanks!

@evanrobertson
Copy link

I've finally had a chance to test this and it works perfectly for my use case. Thanks for getting this change in so quickly.

For anyone that is looking for a way to validate the JWT server side this code should hopefully cover that off in ASP

public static class ApplicationBuilderExtensions
{
    public static IServiceCollection AddSupabaseAuthentication(this IServiceCollection services, string supabaseUrl, string jwtSecret, string supabaseSecretKey)
    {
        services.AddAuthentication(o =>
            {
                o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(o =>
            {
                o.IncludeErrorDetails = true;
                o.SaveToken = true;

                o.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(
                        Encoding.UTF8.GetBytes(jwtSecret)
                    ),
                    ValidateIssuer = false,
                    ValidateAudience = true,
                    ValidAudience = "authenticated",
                };
                o.Events = new JwtBearerEvents()
                {
                    OnTokenValidated = async context =>
                    {
                        if (context.SecurityToken is not JwtSecurityToken accessToken) {
                            context.Fail(new Exception("Could not validate with Supabase"));
                            return;
                        }
                        
                        var options = Supabase.StatelessClient.GetAuthOptions(supabaseUrl, supabaseSecretKey);
                        var user = await Supabase.Gotrue.StatelessClient.GetApi(options).GetUser(accessToken.RawData);

                        if (user == null)
                        {
                            context.Fail("Could not validate Supabase user with token provided");
                        }
                    },
                };
            });
        return services;
    }
}

And to get the token in controllers

var token = await HttpContext.GetTokenAsync(JwtBearerDefaults.AuthenticationScheme, "access_token")

@acupofjose
Copy link
Collaborator

@evanrobertson glad to hear it!

Thanks for the recommendation on the code for validation - you could also do request the user from the token they provide: StatelessClient.Auth.GetUser(token) which should fail if they have an invalid token and succeed with the user’s object if valid.

But! That’s an API call to do that, I like that your solution doesn’t have to hit supabase again to validate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants