Get invitation details
Retrieve information about an invitation using its token:
const invite = await authClient . invite . get ({
token: "invitation-token" ,
});
Response structure
{
"status" : true ,
"inviter" : {
"email" : "[email protected] " ,
"name" : "Admin User" ,
"image" : "https://example.com/avatar.jpg"
},
"invitation" : {
"email" : "[email protected] " ,
"createdAt" : "2024-03-04T10:00:00.000Z" ,
"role" : "member" ,
"newAccount" : true
}
}
Access control
Private invites
Public invites
For invitations with an email address, only the invited user can retrieve details: // Only works if logged in as [email protected]
const invite = await authClient . invite . get ({
token: "private-invite-token" ,
});
If the logged-in user’s email doesn’t match the invite email, the request fails with INVALID_TOKEN. Anyone can retrieve details for public invitations (without email): // Works for anyone, even without authentication
const invite = await authClient . invite . get ({
token: "public-invite-token" ,
});
Use cases
Display invitation preview
function InvitePreview ({ token } : { token : string }) {
const [ invite , setInvite ] = useState ( null );
const [ loading , setLoading ] = useState ( true );
useEffect (() => {
authClient . invite . get ({ token })
. then ( setInvite )
. catch (() => alert ( "Invalid invitation" ))
. finally (() => setLoading ( false ));
}, [ token ]);
if ( loading ) return < p > Loading... </ p > ;
if ( ! invite ) return < p > Invitation not found </ p > ;
return (
< div >
< h2 > You've been invited! </ h2 >
< p > { invite . inviter . name } invited you to join as { invite . invitation . role } </ p >
< p >
{ invite . invitation . newAccount
? "Create your account to accept"
: "Sign in to accept this invitation" }
</ p >
</ div >
);
}
Validate invite before showing signup form
Cancel an invitation
Cancel an invitation you created. Only the user who created the invite can cancel it.
const result = await authClient . invite . cancel ({
token: "invitation-token" ,
});
// Result: { status: true, message: "Invite cancelled successfully" }
Requirements
You must be logged in
You must be the user who created the invitation
The invitation must have pending status
The canCancelInvite permission check must pass
Permission checks
The server respects your canCancelInvite configuration:
invite ({
canCancelInvite : async ({ inviterUser , invitation , ctx }) => {
// Only admins can cancel admin invitations
if ( invitation . role === 'admin' && inviterUser . role !== 'admin' ) {
return false ;
}
return true ;
},
})
Cleanup behavior
Depending on your server configuration:
The invitation is marked as canceled but remains in the database: UPDATE invite SET status = 'canceled' WHERE id = ?;
The invitation and its usage records are deleted: DELETE FROM inviteUse WHERE inviteId = ?;
DELETE FROM invite WHERE token = ?;
function CancelInviteButton ({ token } : { token : string }) {
const [ loading , setLoading ] = useState ( false );
const handleCancel = async () => {
if ( ! confirm ( "Are you sure you want to cancel this invitation?" )) {
return ;
}
setLoading ( true );
try {
await authClient . invite . cancel ({ token });
alert ( "Invitation cancelled" );
} catch ( error ) {
if ( error . errorCode === "INSUFFICIENT_PERMISSIONS" ) {
alert ( "You don't have permission to cancel this invite" );
} else if ( error . errorCode === "INVALID_TOKEN" ) {
alert ( "This invitation is no longer valid" );
} else {
alert ( "Failed to cancel invitation" );
}
} finally {
setLoading ( false );
}
};
return (
< button onClick = { handleCancel } disabled = { loading } >
{ loading ? "Cancelling..." : "Cancel Invitation" }
</ button >
);
}
Reject an invitation
Reject an invitation sent to you. Only available for private invites, and only the recipient can reject.
const result = await authClient . invite . reject ({
token: "invitation-token" ,
});
// Result: { status: true, message: "Invite rejected successfully" }
Requirements
You must be logged in
The invitation must be a private invite (with email)
Your email must match the invitation email
The invitation must have pending status
The canRejectInvite permission check must pass
Permission checks
invite ({
canRejectInvite : async ({ inviteeUser , invitation , ctx }) => {
// Custom logic to control rejections
return true ;
},
})
Public invites cannot be rejected
Attempting to reject a public invite fails:
try {
await authClient . invite . reject ({ token: "public-invite-token" });
} catch ( error ) {
// error.errorCode === "CANT_REJECT_INVITE"
}
Cleanup behavior
Same as cancel - respects cleanupInvitesOnDecision configuration.
function RejectInviteButton ({ token } : { token : string }) {
const handleReject = async () => {
if ( ! confirm ( "Are you sure you want to reject this invitation?" )) {
return ;
}
try {
await authClient . invite . reject ({ token });
alert ( "Invitation rejected" );
} catch ( error ) {
if ( error . errorCode === "CANT_REJECT_INVITE" ) {
alert ( "You cannot reject this invitation" );
} else if ( error . errorCode === "INVALID_TOKEN" ) {
alert ( "This invitation is no longer valid" );
} else {
alert ( "Failed to reject invitation" );
}
}
};
return < button onClick = { handleReject } > Reject Invitation </ button > ;
}
Invitation lifecycle
Understanding invitation states:
Status values
Initial state. Invitation is active and can be accepted.
Invitation was successfully accepted and reached max uses.
Creator cancelled the invitation.
Recipient rejected the invitation (private invites only).
Status transitions
Only pending invitations can be:
Accepted (activated)
Canceled by creator
Rejected by recipient
Once an invitation changes to used, canceled, or rejected, it cannot be used or modified.
Example: Invitation management dashboard
import { useState , useEffect } from "react" ;
import { authClient } from "@/lib/auth-client" ;
function InviteManagement () {
const [ invites , setInvites ] = useState ([]);
// Note: You'll need to implement a server endpoint to list invites
// The invite plugin doesn't include a list endpoint by default
const handleCancel = async ( token : string ) => {
try {
await authClient . invite . cancel ({ token });
// Refresh list
setInvites ( invites . filter ( i => i . token !== token ));
} catch ( error ) {
alert ( "Failed to cancel invitation" );
}
};
return (
< div >
< h2 > Pending Invitations </ h2 >
< table >
< thead >
< tr >
< th > Email </ th >
< th > Role </ th >
< th > Created </ th >
< th > Uses </ th >
< th > Actions </ th >
</ tr >
</ thead >
< tbody >
{ invites . map ( invite => (
< tr key = { invite . token } >
< td > { invite . email || "(Public invite)" } </ td >
< td > { invite . role } </ td >
< td > {new Date ( invite . createdAt ). toLocaleDateString () } </ td >
< td > { invite . usedCount } / { invite . maxUses } </ td >
< td >
< button onClick = { () => handleCancel ( invite . token ) } >
Cancel
</ button >
</ td >
</ tr >
)) }
</ tbody >
</ table >
</ div >
);
}
The invite plugin provides individual invite operations but doesn’t include a “list all invites” endpoint. You’ll need to query the database directly or create a custom endpoint for this functionality.
Server-side operations
You can also manage invites from your server:
import { auth } from "./auth" ;
// Get invite details
const invite = await auth . api . getInvite ({
query: { token: "invitation-token" },
headers: request . headers ,
});
// Cancel invite
const result = await auth . api . cancelInvite ({
body: { token: "invitation-token" },
headers: request . headers ,
});
// Reject invite
const result = await auth . api . rejectInvite ({
body: { token: "invitation-token" },
headers: request . headers ,
});
Cleanup strategies
Choose how to handle completed invitations:
Keep historical data (default)
invite ({
cleanupInvitesOnDecision: false ,
cleanupInvitesAfterMaxUses: false ,
})
Maintains full audit trail of all invitations and their usage.
Automatic cleanup
invite ({
cleanupInvitesOnDecision: true , // Delete when canceled/rejected
cleanupInvitesAfterMaxUses: true , // Delete when fully used
})
Reduces database size by removing completed invitations.
Manual cleanup
Implement a cron job to delete old invitations:
// Run daily
await db . delete ( invite )
. where (
and (
eq ( invite . status , 'used' ),
lt ( invite . expiresAt , new Date ( Date . now () - 30 * 24 * 60 * 60 * 1000 ))
)
);
Error codes
Token doesn’t exist, is expired, or invitation status is not pending.
User lacks permission to perform the operation.
Either the invite is public, or the user’s email doesn’t match the invite email.
The user who created the invitation no longer exists.
Next steps
Hooks and callbacks Respond to invitation lifecycle events
Email integration Configure email sending for invitations