diff --git a/packages/pl-fe/src/actions/auth.ts b/packages/pl-fe/src/actions/auth.ts index 1eed939d6..a9ffc168a 100644 --- a/packages/pl-fe/src/actions/auth.ts +++ b/packages/pl-fe/src/actions/auth.ts @@ -125,7 +125,7 @@ const createUserToken = (username: string, password: string) => }; return obtainOAuthToken(params) - .then((token) => dispatch(authLoggedIn(token))); + .then((token) => dispatch(authLoggedIn(token, app))); }; const otpVerify = (code: string, mfa_token: string) => @@ -142,7 +142,7 @@ const otpVerify = (code: string, mfa_token: string) => challenge_type: 'totp', // redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', // scope: getScopes(getState()), - }).then((token) => dispatch(authLoggedIn(token))); + }).then((token) => dispatch(authLoggedIn(token, app))); }; interface VerifyCredentialsRequestAction { @@ -243,10 +243,12 @@ const logOut = () => if (!account) return dispatch(noOp); + const token = state.auth.users[account.url]!.access_token; + const params = { - client_id: state.auth.app?.client_id!, - client_secret: state.auth.app?.client_secret!, - token: state.auth.users[account.url]!.access_token, + client_id: state.auth.tokens[token]?.client_id || state.auth.app?.client_id!, + client_secret: state.auth.tokens[token]?.client_secret || state.auth.app?.client_secret!, + token, }; return dispatch(revokeOAuthToken(params)) @@ -294,14 +296,15 @@ const fetchOwnAccounts = () => }; const register = (params: CreateAccountParams) => - (dispatch: AppDispatch) => { + async (dispatch: AppDispatch) => { params.fullname = params.username; - return dispatch(createAppAndToken()) - .then(() => dispatch(createAccount(params))) + const { app } = await dispatch(createAppAndToken()); + + return dispatch(createAccount(params)) .then(({ token }: { token: Token }) => { dispatch(startOnboarding()); - return dispatch(authLoggedIn(token)); + return dispatch(authLoggedIn(token, app)); }); }; @@ -311,11 +314,12 @@ const fetchCaptcha = () => interface AuthLoggedInAction { type: typeof AUTH_LOGGED_IN; token: Token; + app?: CredentialApplication; } -const authLoggedIn = (token: Token) => +const authLoggedIn = (token: Token, app?: CredentialApplication | null) => (dispatch: AppDispatch) => { - dispatch({ type: AUTH_LOGGED_IN, token }); + dispatch({ type: AUTH_LOGGED_IN, token, app: app || undefined }); return token; }; diff --git a/packages/pl-fe/src/actions/external-auth.ts b/packages/pl-fe/src/actions/external-auth.ts index 191ffe870..cd22781b7 100644 --- a/packages/pl-fe/src/actions/external-auth.ts +++ b/packages/pl-fe/src/actions/external-auth.ts @@ -73,7 +73,8 @@ const externalLogin = (host: string) => { const loginWithCode = (code: string) => (dispatch: AppDispatch) => { - const { client_id, client_secret, redirect_uri } = JSON.parse(localStorage.getItem('plfe:external:app')!); + const app = JSON.parse(localStorage.getItem('plfe:external:app')!); + const { client_id, client_secret, redirect_uri } = app; const baseURL = localStorage.getItem('plfe:external:baseurl')!; const scope = localStorage.getItem('plfe:external:scopes')!; @@ -87,7 +88,7 @@ const loginWithCode = (code: string) => }; return obtainOAuthToken(params, baseURL) - .then((token) => dispatch(authLoggedIn(token))) + .then((token) => dispatch(authLoggedIn(token, app))) .then(({ access_token }) => dispatch(verifyCredentials(access_token, baseURL))) .then((account) => dispatch(switchAccount(account.id))) .then(() => window.location.href = '/'); diff --git a/packages/pl-fe/src/reducers/auth.ts b/packages/pl-fe/src/reducers/auth.ts index 7d5e4a94e..f1083a725 100644 --- a/packages/pl-fe/src/reducers/auth.ts +++ b/packages/pl-fe/src/reducers/auth.ts @@ -44,6 +44,14 @@ const authUserSchema = v.object({ url: v.string(), }); +const tokenWithAppSchema = v.object({ + ...tokenSchema.entries, + client_id: v.fallback(v.optional(v.string()), undefined), + client_secret: v.fallback(v.optional(v.string()), undefined), +}); + +type TokenWithApp = v.InferOutput; + interface AuthUser { access_token: string; id: string; @@ -52,7 +60,7 @@ interface AuthUser { interface State { app: CredentialApplication | null; - tokens: Record; + tokens: Record; users: Record; me: string | null; client: InstanceType; @@ -78,7 +86,7 @@ const getLocalState = (): State | undefined => { return ({ app: state.app && v.parse(applicationSchema, state.app), - tokens: Object.fromEntries(Object.entries(state.tokens).map(([key, value]) => [key, v.parse(tokenSchema, value)])), + tokens: Object.fromEntries(Object.entries(state.tokens).map(([key, value]) => [key, v.parse(tokenWithAppSchema, value)])), users: Object.fromEntries(Object.entries(state.users).map(([key, value]) => [key, v.parse(authUserSchema, value)])), me: state.me, client: new PlApiClient(parseBaseURL(state.me) || backendUrl, state.users[state.me]?.access_token), @@ -189,8 +197,12 @@ const initialState: State = initialize({ ...localState, }); -const importToken = (state: State | Draft, token: Token) => { - state.tokens[token.access_token] = token; +const importToken = (state: State | Draft, token: Token, app?: CredentialApplication) => { + state.tokens[token.access_token] = { + client_id: app?.client_id, + client_secret: app?.client_secret, + ...token, + }; }; // Users are now stored by their ActivityPub ID instead of their @@ -309,7 +321,7 @@ const reducer = (state: State, action: Action): State => { }); case AUTH_LOGGED_IN: return updateState(state, (draft) => { - importToken(draft, action.token); + importToken(draft, action.token, action.app); }); case AUTH_LOGGED_OUT: return updateState(state, (draft) => {