Add init link.

This commit is contained in:
Chris Chen
2026-06-24 10:53:13 -07:00
parent e88ea7917f
commit e53cea7a82
20 changed files with 971 additions and 11 deletions
@@ -64,6 +64,14 @@ export interface LoginResult {
message?: string;
}
/** Matches the C# ValidateInvitationResult DTO. */
export interface ValidateInvitationResult {
valid: boolean;
expired: boolean;
memberName?: string;
email?: string;
}
export interface TokenVerificationResult {
isValid: boolean;
/** Constructed from JWT claims when using secret-link login. */
@@ -177,6 +185,36 @@ export class AuthService {
);
}
/**
* Checks whether an invitation token is still usable (anonymous). Used by the
* public "set your password" page to decide what to show before the member types.
*/
validateInvitation(token: string): Observable<ValidateInvitationResult> {
return this.http.get<ValidateInvitationResult>(
`${this.apiConfig.authUrl}/invitation/validate`,
{ params: { token } }
);
}
/**
* Consumes an invitation: sets the password and logs the member in. On success the
* server returns a normal login payload, so we store the access token + user (and the
* refresh cookie is set server-side) exactly like login(). Errors propagate to the caller.
*/
acceptInvitation(token: string, newPassword: string): Observable<UserInfo> {
return this.http.post<ApiLoginResponse>(
`${this.apiConfig.authUrl}/accept-invitation`,
{ token, newPassword },
{ withCredentials: true }
).pipe(
tap(response => {
this.accessToken$.next(response.accessToken);
this.currentUser$.next(response.user);
}),
map(response => response.user)
);
}
/**
* Clears in-memory auth state immediately, then fires a fire-and-forget
* POST to revoke the server-side refresh token cookie.