Create flow to add password after account activation

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-02-17 17:08:05 +04:00
parent 5ab5d2cc4c
commit 7971f88fcd
10 changed files with 313 additions and 143 deletions

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<b79143becc90a4776f321d0e91db49bd>> * @generated SignedSource<<852ecee082c322aba273f04575353fbd>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -10,7 +10,6 @@
import { ConcreteRequest } from 'relay-runtime'; import { ConcreteRequest } from 'relay-runtime';
export type ActivateAccountInput = { export type ActivateAccountInput = {
password?: string | null | undefined;
token: string; token: string;
}; };
export type ActivateAccountPageMutation$variables = { export type ActivateAccountPageMutation$variables = {
@@ -18,9 +17,7 @@ export type ActivateAccountPageMutation$variables = {
}; };
export type ActivateAccountPageMutation$data = { export type ActivateAccountPageMutation$data = {
readonly activateAccount: { readonly activateAccount: {
readonly profile: { readonly createPasswordToken: string | null | undefined;
readonly id: string;
} | null | undefined;
} | null | undefined; } | null | undefined;
}; };
export type ActivateAccountPageMutation = { export type ActivateAccountPageMutation = {
@@ -54,19 +51,8 @@ v1 = [
{ {
"alias": null, "alias": null,
"args": null, "args": null,
"concreteType": "Profile", "kind": "ScalarField",
"kind": "LinkedField", "name": "createPasswordToken",
"name": "profile",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
}
],
"storageKey": null "storageKey": null
} }
], ],
@@ -91,16 +77,16 @@ return {
"selections": (v1/*: any*/) "selections": (v1/*: any*/)
}, },
"params": { "params": {
"cacheID": "57d92d0ae2a6220af84fbd9fe27f7aa3", "cacheID": "388c90522ecf3a3365e171a623fb2d2e",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "ActivateAccountPageMutation", "name": "ActivateAccountPageMutation",
"operationKind": "mutation", "operationKind": "mutation",
"text": "mutation ActivateAccountPageMutation(\n $input: ActivateAccountInput!\n) {\n activateAccount(input: $input) {\n profile {\n id\n }\n }\n}\n" "text": "mutation ActivateAccountPageMutation(\n $input: ActivateAccountInput!\n) {\n activateAccount(input: $input) {\n createPasswordToken\n }\n}\n"
} }
}; };
})(); })();
(node as any).hash = "0e073ce00eb7c435a875b5797f3e6db0"; (node as any).hash = "c27b723383934423bf92926820426653";
export default node; export default node;

View File

@@ -0,0 +1,93 @@
/**
* @generated SignedSource<<cde2278cb4ed7c350f1c8727933cd92d>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type ResetPasswordInput = {
password: string;
token: string;
};
export type CreatePasswordPageMutation$variables = {
input: ResetPasswordInput;
};
export type CreatePasswordPageMutation$data = {
readonly resetPassword: {
readonly success: boolean;
} | null | undefined;
};
export type CreatePasswordPageMutation = {
response: CreatePasswordPageMutation$data;
variables: CreatePasswordPageMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "ResetPasswordPayload",
"kind": "LinkedField",
"name": "resetPassword",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "success",
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "CreatePasswordPageMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "CreatePasswordPageMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "aedb0b874e2e55a106724665d51f840e",
"id": null,
"metadata": {},
"name": "CreatePasswordPageMutation",
"operationKind": "mutation",
"text": "mutation CreatePasswordPageMutation(\n $input: ResetPasswordInput!\n) {\n resetPassword(input: $input) {\n success\n }\n}\n"
}
};
})();
(node as any).hash = "d9bd91787098b9272f0046ad09554a1a";
export default node;

View File

@@ -7,16 +7,14 @@ import { useMutation } from "react-relay";
import { Link, useNavigate, useSearchParams } from "react-router"; import { Link, useNavigate, useSearchParams } from "react-router";
import { graphql } from "relay-runtime"; import { graphql } from "relay-runtime";
import type { ActivateAccountPageMutation } from "#/__generated__/iam/ActivateAccountPageMutation.graphql"; import type { ActivateAccountPageMutation$data, ActivateAccountPageMutation } from "#/__generated__/iam/ActivateAccountPageMutation.graphql";
const activateAccountMutation = graphql` const activateAccountMutation = graphql`
mutation ActivateAccountPageMutation( mutation ActivateAccountPageMutation(
$input: ActivateAccountInput! $input: ActivateAccountInput!
) { ) {
activateAccount(input: $input) { activateAccount(input: $input) {
profile { createPasswordToken
id
}
} }
} }
`; `;
@@ -39,7 +37,7 @@ export default function ActivateAccountPage() {
variables: { variables: {
input: { token }, input: { token },
}, },
onCompleted: (_, errors: GraphQLError[] | null) => { onCompleted: (response: ActivateAccountPageMutation$data, errors: GraphQLError[] | null) => {
if (errors) { if (errors) {
for (const err of errors) { for (const err of errors) {
if (err.extensions?.code === "ALREADY_AUTHENTICATED") { if (err.extensions?.code === "ALREADY_AUTHENTICATED") {
@@ -63,7 +61,21 @@ export default function ActivateAccountPage() {
), ),
variant: "success", variant: "success",
}); });
void navigate("/", { replace: true });
const { activateAccount } = response;
if (!activateAccount) {
throw new Error("mutation data missing");
}
if (activateAccount.createPasswordToken) {
void navigate(
{ pathname: "/auth/create-password", search: `?token=${activateAccount.createPasswordToken}` },
{ replace: true },
);
} else {
void navigate("/", { replace: true });
}
}, },
onError: (e) => { onError: (e) => {
toast({ toast({

View File

@@ -0,0 +1,114 @@
import { formatError } from "@probo/helpers";
import { usePageTitle } from "@probo/hooks";
import { useTranslate } from "@probo/i18n";
import { Button, Field, useToast } from "@probo/ui";
import { useMutation } from "react-relay";
import { Link, useNavigate, useSearchParams } from "react-router";
import { graphql } from "relay-runtime";
import { z } from "zod";
import type { CreatePasswordPageMutation } from "#/__generated__/iam/CreatePasswordPageMutation.graphql";
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
const createPasswordMutation = graphql`
mutation CreatePasswordPageMutation($input: ResetPasswordInput!) {
resetPassword(input: $input) {
success
}
}
`;
const schema = z.object({
password: z.string().min(8),
});
export default function CreatePasswordPage() {
const { __ } = useTranslate();
const { toast } = useToast();
const [searchParams] = useSearchParams();
const navigate = useNavigate();
usePageTitle(__("Create Password"));
const { register, handleSubmit, formState } = useFormWithSchema(schema, {
defaultValues: {
password: "",
},
});
const [createPassword, isCreatingPassword] = useMutation<CreatePasswordPageMutation>(createPasswordMutation);
const onSubmit = (data: z.infer<typeof schema>) => {
createPassword({
variables: {
input: {
password: data.password,
token: searchParams.get("token") ?? "",
},
},
onCompleted: (_, e) => {
if (e) {
toast({
title: __("Password creation failed"),
description: formatError(__("Password creation failed"), e),
variant: "error",
});
return;
}
toast({
title: __("Success"),
description: __("Account created successfully"),
variant: "success",
});
void navigate("/auth/login", { replace: true });
},
onError: (e) => {
toast({
title: __("Password creation failed"),
description: e.message,
variant: "error",
});
},
});
};
return (
<div className="space-y-6 w-full max-w-md mx-auto pt-8">
<div className="space-y-2 text-center">
<h1 className="text-3xl font-bold">{__("Create a password")}</h1>
<p className="text-txt-tertiary">
{__("Set a password for your account, with at least 8 characters")}
</p>
</div>
<form onSubmit={e => void handleSubmit(onSubmit)(e)} className="space-y-4">
<Field
label={__("Password")}
type="password"
placeholder="••••••••"
{...register("password")}
required
error={formState.errors.password?.message}
/>
<Button type="submit" className="w-xs h-10 mx-auto mt-6" disabled={formState.isLoading || isCreatingPassword}>
{__("Save")}
</Button>
</form>
<div className="text-center">
<p className="text-sm text-txt-tertiary">
{__("Already have an account?")}
{" "}
<Link
to="/auth/login"
className="underline text-txt-primary hover:text-txt-secondary"
>
{__("Log in here")}
</Link>
</p>
</div>
</div>
);
}

View File

@@ -68,6 +68,12 @@ const routes = [
() => import("./pages/iam/auth/ActivateAccountPage"), () => import("./pages/iam/auth/ActivateAccountPage"),
), ),
}, },
{
path: "create-password",
Component: lazy(
() => import("./pages/iam/auth/CreatePasswordPage"),
),
},
{ {
path: "forgot-password", path: "forgot-password",
Component: lazy(() => import("./pages/iam/auth/ForgotPasswordPage")), Component: lazy(() => import("./pages/iam/auth/ForgotPasswordPage")),

View File

@@ -45,7 +45,7 @@ type (
NewPassword string NewPassword string
} }
CreateIdentityFromInvitationRequest struct { ActivateAccountRequest struct {
InvitationToken string InvitationToken string
} }
@@ -87,7 +87,7 @@ func NewAuthService(svc *Service) *AuthService {
return &AuthService{Service: svc} return &AuthService{Service: svc}
} }
func (req CreateIdentityFromInvitationRequest) Validate() error { func (req ActivateAccountRequest) Validate() error {
v := validator.New() v := validator.New()
v.Check(req.InvitationToken, "invitationToken", validator.NotEmpty()) v.Check(req.InvitationToken, "invitationToken", validator.NotEmpty())
@@ -132,8 +132,8 @@ func (req CreateIdentityWithPasswordRequest) Validate() error {
func (s *AuthService) ActivateAccount( func (s *AuthService) ActivateAccount(
ctx context.Context, ctx context.Context,
req *CreateIdentityFromInvitationRequest, req *ActivateAccountRequest,
) (*coredata.MembershipProfile, *coredata.Session, error) { ) (*coredata.MembershipProfile, *string, error) {
if err := req.Validate(); err != nil { if err := req.Validate(); err != nil {
return nil, nil, fmt.Errorf("invalid request: %w", err) return nil, nil, fmt.Errorf("invalid request: %w", err)
} }
@@ -144,11 +144,12 @@ func (s *AuthService) ActivateAccount(
} }
var ( var (
scope = coredata.NewScopeFromObjectID(payload.Data.InvitationID) scope = coredata.NewScopeFromObjectID(payload.Data.InvitationID)
invitation = &coredata.Invitation{} invitation = &coredata.Invitation{}
profile *coredata.MembershipProfile profile *coredata.MembershipProfile
session *coredata.Session identity *coredata.Identity
now = time.Now() now = time.Now()
createPasswordToken *string
) )
err = s.pg.WithTx( err = s.pg.WithTx(
@@ -185,7 +186,7 @@ func (s *AuthService) ActivateAccount(
} }
} }
identity := &coredata.Identity{} identity = &coredata.Identity{}
if err := identity.LoadByID(ctx, tx, profile.IdentityID); err != nil { if err := identity.LoadByID(ctx, tx, profile.IdentityID); err != nil {
return fmt.Errorf("cannot load identity: %w", err) return fmt.Errorf("cannot load identity: %w", err)
} }
@@ -220,12 +221,6 @@ func (s *AuthService) ActivateAccount(
return fmt.Errorf("cannot expire pending invitations: %w", err) return fmt.Errorf("cannot expire pending invitations: %w", err)
} }
session = coredata.NewRootSession(identity.ID, coredata.AuthMethodPassword, s.sessionDuration)
err = session.Insert(ctx, tx)
if err != nil {
return fmt.Errorf("cannot insert session: %w", err)
}
return nil return nil
}, },
) )
@@ -234,7 +229,21 @@ func (s *AuthService) ActivateAccount(
return nil, nil, err return nil, nil, err
} }
return profile, session, nil if identity.HashedPassword == nil {
token, err := statelesstoken.NewToken(
s.tokenSecret,
TokenTypePasswordReset,
s.passwordResetTokenValidity,
PasswordResetData{Email: identity.EmailAddress},
)
if err != nil {
return nil, nil, fmt.Errorf("cannot generate password create token: %w", err)
}
createPasswordToken = &token
}
return profile, createPasswordToken, nil
} }
func (s AuthService) ResetPassword( func (s AuthService) ResetPassword(

View File

@@ -796,13 +796,10 @@ type SignOutPayload {
} }
type ActivateAccountPayload { type ActivateAccountPayload {
createPasswordToken: String
profile: Profile profile: Profile
} }
type CreatePasswordPayload {
success: Boolean!
}
type ForgotPasswordPayload { type ForgotPasswordPayload {
success: Boolean! success: Boolean!
} }

View File

@@ -80,7 +80,8 @@ type ComplexityRoot struct {
} }
ActivateAccountPayload struct { ActivateAccountPayload struct {
Profile func(childComplexity int) int CreatePasswordToken func(childComplexity int) int
Profile func(childComplexity int) int
} }
AssumeOrganizationSessionPayload struct { AssumeOrganizationSessionPayload struct {
@@ -108,10 +109,6 @@ type ComplexityRoot struct {
Organization func(childComplexity int) int Organization func(childComplexity int) int
} }
CreatePasswordPayload struct {
Success func(childComplexity int) int
}
CreatePersonalAPIKeyPayload struct { CreatePersonalAPIKeyPayload struct {
PersonalAPIKeyEdge func(childComplexity int) int PersonalAPIKeyEdge func(childComplexity int) int
Token func(childComplexity int) int Token func(childComplexity int) int
@@ -654,6 +651,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.AcceptInvitationPayload.Membership(childComplexity), true return e.complexity.AcceptInvitationPayload.Membership(childComplexity), true
case "ActivateAccountPayload.createPasswordToken":
if e.complexity.ActivateAccountPayload.CreatePasswordToken == nil {
break
}
return e.complexity.ActivateAccountPayload.CreatePasswordToken(childComplexity), true
case "ActivateAccountPayload.profile": case "ActivateAccountPayload.profile":
if e.complexity.ActivateAccountPayload.Profile == nil { if e.complexity.ActivateAccountPayload.Profile == nil {
break break
@@ -731,13 +734,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.CreateOrganizationPayload.Organization(childComplexity), true return e.complexity.CreateOrganizationPayload.Organization(childComplexity), true
case "CreatePasswordPayload.success":
if e.complexity.CreatePasswordPayload.Success == nil {
break
}
return e.complexity.CreatePasswordPayload.Success(childComplexity), true
case "CreatePersonalAPIKeyPayload.personalAPIKeyEdge": case "CreatePersonalAPIKeyPayload.personalAPIKeyEdge":
if e.complexity.CreatePersonalAPIKeyPayload.PersonalAPIKeyEdge == nil { if e.complexity.CreatePersonalAPIKeyPayload.PersonalAPIKeyEdge == nil {
break break
@@ -3281,13 +3277,10 @@ type SignOutPayload {
} }
type ActivateAccountPayload { type ActivateAccountPayload {
createPasswordToken: String
profile: Profile profile: Profile
} }
type CreatePasswordPayload {
success: Boolean!
}
type ForgotPasswordPayload { type ForgotPasswordPayload {
success: Boolean! success: Boolean!
} }
@@ -4327,6 +4320,35 @@ func (ec *executionContext) fieldContext_AcceptInvitationPayload_invitation(_ co
return fc, nil return fc, nil
} }
func (ec *executionContext) _ActivateAccountPayload_createPasswordToken(ctx context.Context, field graphql.CollectedField, obj *types.ActivateAccountPayload) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_ActivateAccountPayload_createPasswordToken,
func(ctx context.Context) (any, error) {
return obj.CreatePasswordToken, nil
},
nil,
ec.marshalOString2ᚖstring,
true,
false,
)
}
func (ec *executionContext) fieldContext_ActivateAccountPayload_createPasswordToken(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "ActivateAccountPayload",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _ActivateAccountPayload_profile(ctx context.Context, field graphql.CollectedField, obj *types.ActivateAccountPayload) (ret graphql.Marshaler) { func (ec *executionContext) _ActivateAccountPayload_profile(ctx context.Context, field graphql.CollectedField, obj *types.ActivateAccountPayload) (ret graphql.Marshaler) {
return graphql.ResolveField( return graphql.ResolveField(
ctx, ctx,
@@ -4756,35 +4778,6 @@ func (ec *executionContext) fieldContext_CreateOrganizationPayload_membership(_
return fc, nil return fc, nil
} }
func (ec *executionContext) _CreatePasswordPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.CreatePasswordPayload) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_CreatePasswordPayload_success,
func(ctx context.Context) (any, error) {
return obj.Success, nil
},
nil,
ec.marshalNBoolean2bool,
true,
true,
)
}
func (ec *executionContext) fieldContext_CreatePasswordPayload_success(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "CreatePasswordPayload",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Boolean does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _CreatePersonalAPIKeyPayload_personalAPIKeyEdge(ctx context.Context, field graphql.CollectedField, obj *types.CreatePersonalAPIKeyPayload) (ret graphql.Marshaler) { func (ec *executionContext) _CreatePersonalAPIKeyPayload_personalAPIKeyEdge(ctx context.Context, field graphql.CollectedField, obj *types.CreatePersonalAPIKeyPayload) (ret graphql.Marshaler) {
return graphql.ResolveField( return graphql.ResolveField(
ctx, ctx,
@@ -6636,6 +6629,8 @@ func (ec *executionContext) fieldContext_Mutation_activateAccount(ctx context.Co
IsResolver: true, IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name { switch field.Name {
case "createPasswordToken":
return ec.fieldContext_ActivateAccountPayload_createPasswordToken(ctx, field)
case "profile": case "profile":
return ec.fieldContext_ActivateAccountPayload_profile(ctx, field) return ec.fieldContext_ActivateAccountPayload_profile(ctx, field)
} }
@@ -16764,6 +16759,8 @@ func (ec *executionContext) _ActivateAccountPayload(ctx context.Context, sel ast
switch field.Name { switch field.Name {
case "__typename": case "__typename":
out.Values[i] = graphql.MarshalString("ActivateAccountPayload") out.Values[i] = graphql.MarshalString("ActivateAccountPayload")
case "createPasswordToken":
out.Values[i] = ec._ActivateAccountPayload_createPasswordToken(ctx, field, obj)
case "profile": case "profile":
out.Values[i] = ec._ActivateAccountPayload_profile(ctx, field, obj) out.Values[i] = ec._ActivateAccountPayload_profile(ctx, field, obj)
default: default:
@@ -17037,45 +17034,6 @@ func (ec *executionContext) _CreateOrganizationPayload(ctx context.Context, sel
return out return out
} }
var createPasswordPayloadImplementors = []string{"CreatePasswordPayload"}
func (ec *executionContext) _CreatePasswordPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreatePasswordPayload) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, createPasswordPayloadImplementors)
out := graphql.NewFieldSet(fields)
deferred := make(map[string]*graphql.FieldSet)
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("CreatePasswordPayload")
case "success":
out.Values[i] = ec._CreatePasswordPayload_success(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch(ctx)
if out.Invalids > 0 {
return graphql.Null
}
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
for label, dfs := range deferred {
ec.processDeferredGroup(graphql.DeferredGroup{
Label: label,
Path: graphql.GetPath(ctx),
FieldSet: dfs,
Context: ctx,
})
}
return out
}
var createPersonalAPIKeyPayloadImplementors = []string{"CreatePersonalAPIKeyPayload"} var createPersonalAPIKeyPayloadImplementors = []string{"CreatePersonalAPIKeyPayload"}
func (ec *executionContext) _CreatePersonalAPIKeyPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreatePersonalAPIKeyPayload) graphql.Marshaler { func (ec *executionContext) _CreatePersonalAPIKeyPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreatePersonalAPIKeyPayload) graphql.Marshaler {

View File

@@ -39,7 +39,8 @@ type ActivateAccountInput struct {
} }
type ActivateAccountPayload struct { type ActivateAccountPayload struct {
Profile *Profile `json:"profile,omitempty"` CreatePasswordToken *string `json:"createPasswordToken,omitempty"`
Profile *Profile `json:"profile,omitempty"`
} }
type AssumeOrganizationSessionInput struct { type AssumeOrganizationSessionInput struct {
@@ -91,10 +92,6 @@ type CreateOrganizationPayload struct {
Membership *Membership `json:"membership"` Membership *Membership `json:"membership"`
} }
type CreatePasswordPayload struct {
Success bool `json:"success"`
}
type CreatePersonalAPIKeyInput struct { type CreatePersonalAPIKeyInput struct {
Name string `json:"name"` Name string `json:"name"`
ExpiresAt time.Time `json:"expiresAt"` ExpiresAt time.Time `json:"expiresAt"`

View File

@@ -384,9 +384,9 @@ func (r *mutationResolver) SignOut(ctx context.Context) (*types.SignOutPayload,
// ActivateAccount is the resolver for the signUpFromInvitation field. // ActivateAccount is the resolver for the signUpFromInvitation field.
func (r *mutationResolver) ActivateAccount(ctx context.Context, input types.ActivateAccountInput) (*types.ActivateAccountPayload, error) { func (r *mutationResolver) ActivateAccount(ctx context.Context, input types.ActivateAccountInput) (*types.ActivateAccountPayload, error) {
user, session, err := r.iam.AuthService.ActivateAccount( user, createPasswordToken, err := r.iam.AuthService.ActivateAccount(
ctx, ctx,
&iam.CreateIdentityFromInvitationRequest{ &iam.ActivateAccountRequest{
InvitationToken: input.Token, InvitationToken: input.Token,
}, },
) )
@@ -411,11 +411,9 @@ func (r *mutationResolver) ActivateAccount(ctx context.Context, input types.Acti
return nil, gqlutils.Internal(ctx) return nil, gqlutils.Internal(ctx)
} }
w := gqlutils.HTTPResponseWriterFromContext(ctx)
r.sessionCookie.Set(w, session)
return &types.ActivateAccountPayload{ return &types.ActivateAccountPayload{
Profile: types.NewProfile(user), CreatePasswordToken: createPasswordToken,
Profile: types.NewProfile(user),
}, nil }, nil
} }