supabase / gotrue-js Goto Github PK
View Code? Open in Web Editor NEWAn isomorphic Javascript library for Supabase Auth.
License: MIT License
An isomorphic Javascript library for Supabase Auth.
License: MIT License
Hello,
I had an issue on my app and I thought I did something wrong, but I just tried the nextjs/ssr/auth example in the supabase repo, and I also have a problem.
Repro step:
It will redirect you to the index page because the token is expired. And if you click on the static example, you'll have an error :
SSR -> I can't even manually use the refresh token since it's not in the cookie.
Client side -> Weird behavior, it seems that the Auth HOC never use the refresh token, and I have to logout/login.
This is a Hacktoberfest task!
You can read more about Hacktoberfest on our blog and see all tasks on our Hacktoberfest Project Board.
This library isn't working with React native because it tries to access localstorage
.
In ReactNative, there is no localstorage
, it is instead AsyncStorage
. We need to rewrite any calls to localstorage to guard against this. It might be better to split out all storage calls to a helper file so that we can extend it in the future.
I would like to add ".local"
to the list of hosts checked in src/lib/cookies.js
The problem I am facing is when developing a multi-tenanted application in my local environment, I define the tenant in my hosts file as tenant-name.application.local
.
The isSecureEnvironment
method in src/lib/cookies.js
checks the host header to include 127.0.0.1
and localhost
which returns false
, causing the cookie to be set as Secure:
I would like to add ".local"
to the list of hosts checked in src/lib/cookies.js
Changing my hosts file to use tenant-name.application.localhost, however when accessing the application from other machines on the network it might be confusing, calling a remote host that ends with .localhost
.
I believe the .local
tld is fairly commonly used to resolve a machine on your local network.
Adding ".local"
to the array might return some false positives due to the way the values are checked.
EG: [".local", ...].includes(host)
would return true for the fictional vhost: app.localbusiness.com
.
Maybe it would be better suited to change the check from:
if (['localhost', '127.0.0.1'].indexOf(host) > -1) {
return false
}
To:
if (['localhost', '127.0.0.1'].indexOf(host) > -1 || host.endsWith('.local')) {
return false
}
Would be better suited.
Ability to use access token or other credential received from OAuth flow to enable third party auth.
I am using Expo for my app which takes care a lot of the nuances in handling OAuth flows in a React Native / Expo managed app: https://docs.expo.io/guides/authentication/. Right now, trying to use the built-in provider flows from Supabase JS client is not working.
I would like a way to send an access token or other credential received from an OAuth flow to Supabase to facilitate the login.
Not offering third party auth.
When bootstrapping a frontend application, it is useful to block the final render until the application knows if it is authenticated or not.
The base GoTrueClient
instance provides no real method to infer a post-recovery attempt ready state (only emits upon SIGNED_IN
success event).
Would be awesome to augment the base GoTrueClient
to emit an event if a session is not auto-recovered at construction.
Triggers the auto-recovery:
https://github.com/supabase/gotrue-js/blob/4312f53411dc6fdf963f8adb48200cddf9905bd9/src/GoTrueClient.ts#L77
Only emits an event if the session is successfully recovered:
https://github.com/supabase/gotrue-js/blob/4312f53411dc6fdf963f8adb48200cddf9905bd9/src/GoTrueClient.ts#L499
If the Supabase supabase.auth
instance emitted an event in both success and fail cases, then it would be possible to wrap the final render to await a decision:
// Application mounts too early, meaning downstream route guards redirect to login due to an assumed unauthenticated state.
// Mount the application.
app.mount("#app")
// Specifics of state inspection can occur within a route guard.
// All we need to know is that the auth system has fully initialized one way or another.
supabase.auth.onAuthStateChange(() => {
// Mount the application.
app.mount("#app")
})
Currently, I am detecting the state change (on success) within the app's central authentication state manager and redirecting if the user is already on the login page, however, this is ugly/bad UX, so a pre-render blocking solution would be preferable.
A second alternative I tried previously was to race a Promise
with a timeout, but that felt horribly un-atomic, which is why I landed on the prior alternative:
Promise.race([
() =>
new Promise<void>((resolve) => {
setTimeout(resolve, 100)
}),
() =>
new Promise<void>((resolve) => {
supabase.auth.onAuthStateChange((event) => {
if (event === "SIGNED_IN") {
resolve()
}
})
})
]).then(() => {
app.mount("#app")
})
When using the following app templates with SWR to fetch data on an interval the token refresh does not work. After one hour I get 401 Unauthorized responses from the API route. Only after reloading the app the token gets refreshed.
https://github.com/supabase/gotrue-js/tree/master/example/next
https://github.com/supabase/gotrue-js/blob/master/example/next/pages/index.js
https://github.com/supabase/supabase/tree/master/examples/nextjs-with-supabase-auth
localStorage
field in options
of the createClient
method doesn't support type for AsyncStorage.
I tried to use supabase authentication in the React Native TypeScript mobile application.
In React Native application, it uses the AsyncStorage as a storage.
When I pass the AsyncStorage as a localStorage, it triggers Type AsyncStorageStatic is missing the following properties from type Storage.
error.
import { createClient } from '@supabase/supabase-js'
import AsyncStorage from '@react-native-community/async-storage'
export const supabase = createClient(
URL, API_KEY, {
localStorage: AsyncStorage
}
)
localStorage should support type for AsyncStorage.
Causes errors in some environments
Each time I leave the app open for a few hours, I come back to this error:
TypeError: undefined is not an object (evaluating 'this.currentSession')
- node_modules/react-native/Libraries/LogBox/LogBox.js:148:8 in registerError
- node_modules/react-native/Libraries/LogBox/LogBox.js:59:8 in errorImpl
- node_modules/react-native/Libraries/LogBox/LogBox.js:33:4 in console.error
- node_modules/expo/build/environment/react-native-logs.fx.js:27:4 in error
- node_modules/react-native/Libraries/Core/ExceptionsManager.js:104:6 in reportException
- node_modules/react-native/Libraries/Core/ExceptionsManager.js:171:19 in handleException
- node_modules/react-native/Libraries/Core/setUpErrorHandling.js:24:6 in handleError
- node_modules/expo-error-recovery/build/ErrorRecovery.fx.js:9:32 in ErrorUtils.setGlobalHandler$argument_0
- node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
- node_modules/regenerator-runtime/runtime.js:293:29 in invoke
- node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
- node_modules/regenerator-runtime/runtime.js:154:27 in invoke
- node_modules/regenerator-runtime/runtime.js:164:18 in PromiseImpl.resolve.then$argument_0
- node_modules/react-native/node_modules/promise/setimmediate/core.js:37:13 in tryCallOne
- node_modules/react-native/node_modules/promise/setimmediate/core.js:123:24 in setImmediate$argument_0
- node_modules/react-native/Libraries/Core/Timers/JSTimers.js:130:14 in _callTimer
- node_modules/react-native/Libraries/Core/Timers/JSTimers.js:181:14 in _callImmediatesPass
- node_modules/react-native/Libraries/Core/Timers/JSTimers.js:441:30 in callImmediates
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:387:6 in __callImmediates
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:135:6 in __guard$argument_0
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:364:10 in __guard
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:134:4 in flushedQueue
* [native code]:null in flushedQueue
* [native code]:null in invokeCallbackAndReturnFlushedQueue
The error comes from SupabaseClient.js
const constants_1 = require("./lib/constants");
Is this a known issue where currentSession times out while the user has the app open. Is there a work around?
Currently, the Supabase client has an endpoint to request a magic link or a password reset. However, once the user clicks on that link and is redirected back to the application, there is no way to insert that access / refresh token back into the Supabase client. The only way to handle it is to use the GoTrue client, which feels hacky. Additionally, once they have reset their password with the GoTrue client, they will have to log in again with the Supabase client , as I believe they have two separate systems for maintaining a logged in user. (Please correct me if I am wrong here.)
I would like an addition to the Supabase auth api that allows someone to log in directly with an auth token instead of a user name and password. Additionally, it would be nice to have a way to get a new auth token with a refresh token. Basically, a nice wrapper around more of the GoTrue api that integrates with all the things you have built.
I've thought about just using GoTrue directly for everything. However, I think that might cause problems with PostRest authentication, though I didn't get far enough to find out.
Initializing the client doesn't recover the session from AsyncStorage
Steps to reproduce the behavior, please provide code snippets or a repository:
Session should be restored when opening the app
If applicable, add screenshots to help explain your problem.
If I uncomment these lines then everything works as expected. (https://github.com/supabase/gotrue-js/blob/master/src/GoTrueClient.ts
)
//should be handle on _recoverSession method already
this._saveSession(currentSession)
this._notifyAllSubscribers('SIGNED_IN')
Looks like globalThis isn't globally supported
https://codesandbox.io/s/github/supabase/supabase/tree/master/examples/nextjs-todo-list
Perhaps we should we polyfill this, or we need to change it from globalThis
?
The signOut function never calls this.api.signOut
because it's first removing the current session with this._removeSession()
, then later checks for this.currentSession
before calling this.api.signOut
, so this.api.signOut
never gets called.
Essentially, no logout is ever taking place. The code is only removing the current session.
The result of this is that if you look in the log table you only see login events, even if you log in, log out, log in, log out, etc.
async signOut(): Promise<{ error: Error | null }> {
this._removeSession()
this._notifyAllSubscribers('SIGNED_OUT')
if (this.currentSession) {
const { error } = await this.api.signOut(this.currentSession.access_token)
if (error) return { error }
}
return { error: null }
}
Remember Me
functionality to the example: https://github.com/supabase/gotrue-js/blob/6d2ef91f738b8ee5339e4b3724f432acc1665ad2/example/src/App.js#L33We should give a basic example of how to use enable/disable storing of sessions
Give the ability for developers to redirect their users to a specified URL after they are logged in.
This is especially important for branch deploys
Test case:
test('signUp() the same user twice should throw an error', async () => {
let { error, data } = await api.signUpWithEmail(email, password)
expect(error?.message).toBe('Error sending confirmation mail')
// expect(error?.message).toBe('A user with this email address has already been registered')
expect(data).toBeNull()
})
It would be more helpful to show that there is a "conflict", but at the moment it shows an obscure error: Error sending confirmation mail
Related: #45 (comment)
It would be great if Subscription
(and thus supabase.auth.onAuthStateChange
) would work across browser tabs; this was the behavior I actually expected (although maybe I was overly optimistic).
The usecase I am after is to reactively synchronize authentication changes between tabs. If a user signs out on one tab, the second tab should reflect this change of authentication state.
One alternative is synchronizing authentication state by separate means somehow (e.g. using realtime subscriptions and a dedicated table); but as an app developing this is more effort than it is worth, and I would probably just go with the alternative of not bothering to synch browser tab authentication.
swr
uses revalidate on focus: https://swr.vercel.app/docs/revalidation#revalidate-on-focus
Since the call to _recoverSession
is async, it means that currentSession
and currentUser
isn't populated by the constructor, and that clients need to wait for the stateChangeEmmitter to fire.
This is causing a lot of problems [1] [2]
LocalStorage is synchronous, so we can remove the await. However we will need a way to handle it for ReactNative.
Is there a way we can handle it for both situations?
Side note - I have seen some people complaining that globalThis is undefined. This is also related to storage. Should this also be updated to something that works everywhere?
on the backend you can:
DELETE /admin/users/{user_id}
but the JWT role needs to be service_role
or supabase_admin
perhaps we should add it as a method here
linked: supabase/auth#79
After initialising supabase client with
createClient(supabaseUrl, supabaseKey, {
localStorage: AsyncStorage as any,
autoRefreshToken: true
});
and setting the JWT expiry to 60 (seconds) on the supabase dashboard, the token does not refresh after 60 seconds have elapsed. Oddly enough, setting the JWT expiry to anything less than 60 triggers the token refresh but it constantly updates without waiting for expiry
Steps to reproduce the behavior, please provide code snippets or a repository:
The token should refresh after the expiry time set on the supabase dashboard
We might want to verify the JWT expiry date locally before sending to the server to query for data, then if there's a refresh_token
stored locally we might be able to refresh it before making the request, or otherwise triggering a listenable event on the client
related: supabase/supabase#889
related: #620
after a successful third party authentication the user will be redirected to:
<your-site-url>/#access_token=xyzabc&expires_in=3600&refresh_token=abcdef&token_type=bearer
<your-site-url>/?access_token=xyzabc&expires_in=3600&refresh_token=abcdef&token_type=bearer
we need a mechanism (if supabase-js) is present on the page -> to check the page url on startup and if these values are present - to use them to set the current session
I find the #
slightly strange, if it's better I can also alter gotrue to use a ?
instead so it's more like parsing query params
If I call supabase.auth.signIn({email}, {redirectTo: "someurl"})
the redirectTo
argument is passed down to https://github.com/supabase/gotrue-js/blob/6332b080c8a50a7120106288303c043a0abf8334/src/GoTrueApi.ts#L90 but then on https://github.com/supabase/gotrue-js/blob/6332b080c8a50a7120106288303c043a0abf8334/src/GoTrueApi.ts#L94 it's not actually used.
Steps to reproduce the behavior, please provide code snippets or a repository:
supabase.auth.signIn({email}, {redirectTo: "someurl"})
/magiclink
on supabase, but the redirectTo
parameter is not there.Note that there is also something weird with the Referer
header that is not set correctly for me (I'm just seeing the hostname), which means that the auth flow is completely broken: the configured site URL is not used, Referer is wrong and redirectTo
is lost in the call stack. I'll open a separate issue about the referer.
Edit: I'm trying to figure out where this referer issue is coming from, I seem to only see it on localhost, so it might be related to the dev server (I'm using svelte and sapper) somehow.
It should be there, if we want to get it back out on the other end :)
When loading a web page with a supabase onAuthStateChange
handler, one would expect the signed in event to fire once the page loads and the connection is established. But due to some recent code changes around how session restore is handled, this basically prevents any event handler from being registered. The SIGNED_IN
event notification is fired as part of the Supabase client constructor.
Steps to reproduce the behavior:
The event handler fires.
The problem is very apparent in a multi-page application/"regular website" with a Supabase connection. I think the issue is especially tied to this commit: 3a670be
I was using 1.7.x before, and the event would fire when the web page loads.
Maybe some kind of event handler buffer could be introduced? Buffer auth events until a handler is added, then fire them all immediately.
Steps to reproduce the behavior, please provide code snippets or a repository:
I believe (and I may be wrong about this) that there should be auth.refresh_tokens records for each logged-in user instance.
Tested using an Angular Ionic PWA on MacOS
// when calling...
const { user, session, error } = await supabase.auth.signUp({
email: userInput.email,
password: userInput.password
});
// and error is:
error: {
message: 'A user with this email address has already been registered',
status: 400
}
error
type is JS Error
, which does not include the status
property, so trying to access error.status
results in ESLint warning Property 'status' does not exist on type 'Error'.ts(2339)
I do not have working hosted project yet.
error
type (AuthError
?) should include status
property.
reported by Omar:
"encountering forced logouts after ~30 min - 1 hour (not sure how long exactly)"
Setting up a nextjs app with supabase based on the example in the supbase repository, I get a functioning app, but the token refresh does not seem to work. After one hour the user is being logged out as the token is not valid anymore.
https://github.com/supabase/supabase/tree/master/examples/nextjs-with-supabase-auth
It looks like our updateUser
function accepts an entire user object:
https://github.com/supabase/gotrue-js/blob/8b61cc39df22cf9e1d546df7e1d06e9b27c51556/src/GoTrueApi.ts#L162
Here is the user object:
https://github.com/supabase/gotrue-js/blob/8b61cc39df22cf9e1d546df7e1d06e9b27c51556/src/lib/types.ts#L12
The app_metadata
field should ideally be updatable by the admin, and not by the user. This means it can be used for things like RBAC (netlify does it here: https://docs.netlify.com/visitor-access/role-based-access-control/)
Note, this is still an inferior system to using Postgres tables, since the user would need to log out/in to refresh their token/roles.
This is a Hacktoberfest task!
You can read more about Hacktoberfest on our blog and see all tasks on our Hacktoberfest Project Board.
At the moment this library uses Isomorphic Unfetch. We want to move it to cross-fetch
Bobbie just migrated postgrest-js
to cross-fetch
: supabase/postgrest-js#109 (comment)
We want to keep all the libraries consistent, so we should migrate this one too.
When logged in, the user can update its password to an empty or invalid password, which would've been rejected at sign up.
Using this code:
async function changePassword(alertData: any) {
const { error } = await supabase.auth.update({
password: alertData.password,
});
if (error) {
setErrorMessage(error.message);
setShowErrorAlert(true);
}
}
changePassword(alertData)
with alertData.password = ""
When using an empty or invalid password, either the client library or the server should return an error.
Yes. Because the gotrue-js types are not exported, they can't be used in downstream library.
Export all types by default.
None
This feature requested will be followed by an additional request to the supabase-js library so that all necessary types (gotrue, supabase, realtime) are available in TypeScript projects.
JWT tokens expire frequently.
Requiring the user to reload the page to refresh the JWT token leads to a poor user experience.
SWR's fetching strategy could act as an inspiration.
The refresh token on page reload feature was implemented by @thorwebdev in #31.
Perhaps you could chime in? ๐
forgotPassword()
to the example: https://github.com/supabase/gotrue-js/blob/6d2ef91f738b8ee5339e4b3724f432acc1665ad2/example/src/App.js#L33We should give a basic example of how to use forgotPassword()
This is a Hacktoberfest task!
You can read more about Hacktoberfest on our blog and see all tasks on our Hacktoberfest Project Board.
We need help with checking and improving the inline comments for this library using JSDoc.
If you've never see JSDoc before, it's the comment that go above functions. For example:
/**
* Creates a new user.
*
* Some longer description can go here.
*
* @param {object} credentials The user login details.
* @param {string} credentials.email The user's email address.
* @param {string} credentials.password The user's password.
*/
async signUp(credentials: { email: string; password: string }) {
// ...
}
I sometime need to pass a session by url, there is function to parse the URI components:
https://github.com/supabase/gotrue-js/blob/286fe863b7d7429dce8bc86984a3ef81771fe7b8/src/GoTrueClient.ts#L211-L253
but no function to generate the URI components from a session.
Here is something I think would work, although not tested:
export default class GoTrueClient {
/**
* Gets a string from session data
* @param options.session Use this session instead of the active session
*/
getUriComponentsFromSession(options?: {
session?: Session
}): { sessionString: string | null; error: Error | null } {
try {
const session = options?.session ?? this.currentSession
if (!session?.access_token) throw new Error('Not logged in.')
const sessionString = [
`access_token=${encodeURIComponent(session.access_token)}`,
`expires_in=${encodeURIComponent(session.expires_in)}`,
`refresh_token=${encodeURIComponent(session.refresh_token)}`,
`token_type=${encodeURIComponent(session.token_type)}`,
].join('&')
return { sessionString, error: null }
} catch (error) {
return { sessionString: null, error }
}
}
}
If this is a desirable feature I can submit a PR.
Jump to the Solution specification
problem:
tried using RLS in node context, is there a step I'm missing?
create table public.posts (
id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
uuid uuid
);
alter table posts enable row level security;
create policy "users can insert only own posts" on public.posts for insert with check (auth.uid() = uuid);
const { createClient } = require("@supabase/supabase-js");
const supabase = createClient(
"https://REF.supabase.co",
"KEY"
);
const main = async () => {
supabase.auth
.signIn({ email: "[email protected]", password: "11" })
.then(() => {
supabase
.from("posts")
.insert([{ uuid: supabase.auth.session().user.id }])
.then(console.log)
.catch(console.log);
})
.catch(console.log);
};
main();
but getting:
{
error: {
hint: null,
details: null,
code: '42501',
message: 'new row violates row-level security policy for table "posts"'
},
data: null,
status: 403,
statusText: 'Forbidden',
body: null
}
Currently, the admin methods like "Delete user" that require a full-access API key (e.g. service_role
key) are documented side-by-side with the more client facing methods like signUp
or signOut
(that I think only require a public API key).
I will likely only use the admin methods in a server-side environment (because I should never send a service_role
key to a client). I will likely not use any of the client-side methods (e.g. signUp
, signIn
, signOut
) in that server-side environment. For the same reasons, I will never use the admin methods in a client-side environment. Thus, it doesn't make any sense to increase the client-side bundle by including methods that will only ever be called on the server-side (and vice versa).
I think this library should be refactored into two separate JavaScript libraries:
service_role
key.And then the documentation should be updated accordingly: split (much like the Firebase Authentication docs and reference) into two sections, one for the admin SDK and one for the client-side SDK.
This is how the Firebase Authentication SDKs are structured and I think it makes a lot of sense to reproduce a similar structuring here with Supabase Auth. Especially because I think that every REST API method included in the GoTrue /admin
endpoints should be reproduced in a server-side admin SDK (e.g. like how the DELETE /admin/users/{user_id}
was wrapped in #85).
For example, I'd like to be able to programmatically create new users without them having to login client-side.
I have everything wrapped in a user context provider. When there is a crash or you open the app after closing it, or even when you go back to it sometimes, it logs you out and you have to log in again. I tried a lot of things, including specifying options and double checking the code. Most of it is adapted from the Expo example. Please let me know your thoughts from the gist below:
https://gist.github.com/rodjoseph/ec6b511ea6ab0a2354b231e31121f736
User session should be recovered when user comes back to the app
I'm building a React Native app, and I'd like the email magic link sign in to work. I can forward the query params over to the application, but the API for initializing the session seems limited
There is a method getSessionFromUrl
: https://github.com/supabase/gotrue-js/blob/0c75bf9e33f5e19403c57113a7a5d27359dd9492/src/GoTrueClient.ts#L258-L262`
It could be extended or refactored to allow a user like myself to pass in the auth query param data manually.
I could technically do this right now in userland by copying some of this logic manually and calling the "private" methods such as this._saveSession(session)
. But that seems nasty :)
I'm happy to help out with a PR if there's not already a solution I'm missing. Thanks!
I am using a SSR authentication flow with Sapper. Since I do not want the user in localStorage, I authenticate via a server route, using the supabase.auth.api
functions. When I login, it redirects to the dashboard fine, which confirms me that the JWT is valid, since I check that on page load. However, once I refresh the page, I get this error message: Error: Invalid token: token contains an invalid number of segments
.
Here is my code, as I it may be possible the error is in my code/I am missing something.
// /server.ts
[... other code]
sapper.middleware({
session: async (req, res) => {
const results = await supabase.auth.api.getUser(req.cookies.supaCookie);
console.log(results); // The error messages are logged by this line, but on login it logs the user correctly.
// Gets the cookies set by Supabase and checks if it's valid
if (results.user) {
return {
userToken: req.cookies.supaCookie
};
}
res.clearCookie('supaCookie'); // This oddly doesn't clear the cookie, but whatever really.
return {
userToken: false
};
}
})
// /src/api/auth.js - called by /signin.svelte
export async function post(req, res) {
const { email, password, authType } = req.body;
let userData = await _signin(email, password);
if (userData) {
res.cookie('supaCookie', userData.access_token, { maxAge: userData.expires_in });
return res.end(JSON.stringify({ success: true }));
// the /signin.svelte page then takes that result and redirects to /dashboard
}
return res.end(JSON.stringify({ success: false }));
}
async function _signin(email, password) {
const { data, error } = await supabase.auth.api.signInWithEmail(email, password);
if (error) {
console.log('Error signing in: ', error.name, error.message);
return false;
}
return data;
}
<!-- /dashboard -->
<script>
import { stores } from '@sapper/app';
const { session } = stores(); // Technically unneeded, comes from a tutorial I am loosely basing this on.
</script>
<script context="module">
export async function preload(page, session) {
let { userToken } = session;
if (!userToken) return this.redirect(302, '/signin');
return userToken;
}
</script>
The JWT should still be valid on refresh. In fact, jwt.io doesn't return any error about the JWT.
I may be misunderstanding the way a JWT works, so if it is my misunderstanding, I am sorry about it! I'm just a bit confused as it seems the token should still be valid. I have only tried this on my development machine, if that changes something.
supabase.auth.signOut() is not deleting the cookie created by setAuthCookie
// /api/login.js
import { supabase } from '@/utils/initSupabase'
export default function handler(req, res) {
supabase.auth.api.setAuthCookie(req, res)
}
// logout.js
import { supabase } from '@/utils/initSupabase'
import { useRouter } from 'next/router'
import { useEffect } from 'react'
export default function Logout() {
const router = useRouter()
useEffect(() => {
async function initialize() {
await supabase.auth.signOut()
router.push('/login')
}
initialize()
})
return <></>
}
It is currently impossible to differentiate errors, e.g: when a user signs up there is a multitude of possible errors (network errors, database errors, etc) and although you can easily check if an error occured (if (res.error !== null) { /**/ }
) it is not possible to know which error happened.
Enum error types:
enum SignUpError {
InvalidEmail,
SignUpsDisabled,
NetworkError,
/* etc */
}
enum SignInError {
InvalidCredentials,
/* etc */
}
export default class GoTrueClient {
// --snip--
signUp(credentials: {
email: string;
password: string;
}): Promise<{ /* success object */ } | SignUpError>;
signIn(credentials: {
email?: string;
password?: string;
provider?: Provider;
}): Promise<{ /* success object */ } | SignInError>;
// --snip--
}
I am not aware of any alternative.
May be just a documentation issue:
I noticed that the docs for auth.signUp() destructures user and error out of the return from signUp(), but the user data is in data. I thought I'd let you know if this is an error. It threw me for a loop until I realized to look at the whole object.
I've been going a little insane over this redirectTo
parameter with auth calls. Whatever I tried passing was not getting sent to the server, despite the fix for #63.
It turns out that setting the Referer
header programmatically is not allowed: https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name
See the steps in #63, but upgrade supabase-js to 1.4.1.
The magic link redirect_to
parameter contains the calling url, not the one passed to gotrue's redirectTo
.
A warning is issued in firefox's console: Attempt to set a forbidden header was denied: referer
The redirection link in the email should match what is passed to the auth call. I'd suggest either passing a different, custom header, or passing the url as part of the body of the request, whichever requires the least changes on the server side.
We need to figure a clean strategy for handling email updates
When a user signs up, GoTrue returns a user
{
"app_metadata": Object {
"provider": "email",
},
"aud": Any<String>,
"confirmed_at": Any<String>,
"created_at": Any<String>,
"email": user@email.com, // user email
"id": Any<String>,
"last_sign_in_at": Any<String>,
"role": "",
"updated_at": Any<String>,
"user_metadata": Object {},
}
then if they update their email using PUT /user
, a completely new field is added
{
"app_metadata": Object {
"provider": "email",
},
"aud": Any<String>,
"confirmed_at": Any<String>,
"created_at": Any<String>,
"email": user@email.com, // original email
"new_email": "[email protected]", // updated email
"email_change_sent_at": "2021-02-15T07:41:15.8564305Z", // new field
"id": Any<String>,
"last_sign_in_at": Any<String>,
"role": "",
"updated_at": Any<String>,
"user_metadata": Object {},
}
If we update again, the original email stays, but the new_email
field is updated.
{
"app_metadata": Object {
"provider": "email",
},
"aud": Any<String>,
"confirmed_at": Any<String>,
"created_at": Any<String>,
"email": user@email.com, // original email
"new_email": "[email protected]", // updated email - changed
"email_change_sent_at": "2021-02-15T07:41:15.8699128Z",
"id": Any<String>,
"last_sign_in_at": Any<String>,
"role": "",
"updated_at": Any<String>,
"user_metadata": Object {},
}
I'm sure there is a reason why it was done this way in GoTrue, but I can't figure out why.
Should we standardise the object in this library so that it always returns the current email?
async function getUser(
jwt: string
): Promise<{ user: User | null; data: User | null; error: Error | null }> {
try {
const data: any = await get(`${this.url}/user`, { headers: this._createRequestHeaders(jwt) })
let user = data
if (data.new_email) user.email = data.new_email
return { user, data, error: null }
} catch (error) {
return { user: null, data: null, error }
}
}
I noticed that this script never exits, I wondered whether it might be something inside the signIn
call
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.