Distinguish expired magic links from invalid tokens
When a magic link token expires, the user now sees a specific
error message ("This magic link has expired. Please request a
new one.") instead of the generic "Failed to connect" error.
This adds ErrExpiredToken to the IAM error types, checks for
statelesstoken.ErrExpiredToken in both GetMagicLinkEmail and
OpenSessionWithMagicLink, and handles it in the trust resolver
and frontend.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
@@ -46,9 +46,16 @@ export default function VerifyMagicLinkPagePageMutation() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const hasExpiredToken = errors.some(
|
||||
(err) => err.message === "token has expired",
|
||||
);
|
||||
|
||||
toast({
|
||||
title: __("Error"),
|
||||
description: formatError(__("Failed to connect"), errors),
|
||||
description: hasExpiredToken
|
||||
? __("This magic link has expired. Please request a new one.")
|
||||
: formatError(__("Failed to connect"), errors),
|
||||
variant: "error",
|
||||
});
|
||||
return;
|
||||
|
||||
@@ -634,6 +634,11 @@ func (s AuthService) SendMagicLink(ctx context.Context, req *SendMagicLinkReques
|
||||
func (s AuthService) GetMagicLinkEmail(ctx context.Context, tokenString string) (mail.Addr, error) {
|
||||
payload, err := statelesstoken.ValidateToken[MagicLinkData](s.tokenSecret, TokenTypeMagicLink, tokenString)
|
||||
if err != nil {
|
||||
var errExpired *statelesstoken.ErrExpiredToken
|
||||
if errors.As(err, &errExpired) {
|
||||
return mail.Nil, NewExpiredTokenError()
|
||||
}
|
||||
|
||||
return mail.Nil, NewInvalidTokenError()
|
||||
}
|
||||
|
||||
@@ -649,6 +654,11 @@ func (s AuthService) OpenSessionWithMagicLink(ctx context.Context, tokenString s
|
||||
|
||||
payload, err := statelesstoken.ValidateToken[MagicLinkData](s.tokenSecret, TokenTypeMagicLink, tokenString)
|
||||
if err != nil {
|
||||
var errExpired *statelesstoken.ErrExpiredToken
|
||||
if errors.As(err, &errExpired) {
|
||||
return nil, nil, nil, NewExpiredTokenError()
|
||||
}
|
||||
|
||||
return nil, nil, nil, NewInvalidTokenError()
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,16 @@ func (e ErrInvalidToken) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
type ErrExpiredToken struct{ message string }
|
||||
|
||||
func NewExpiredTokenError() error {
|
||||
return &ErrExpiredToken{"token has expired"}
|
||||
}
|
||||
|
||||
func (e ErrExpiredToken) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
type ErrInvitationAlreadyAccepted struct{ InvitationID gid.GID }
|
||||
|
||||
func NewInvitationAlreadyAcceptedError(invitationID gid.GID) error {
|
||||
|
||||
@@ -225,6 +225,11 @@ func (r *mutationResolver) VerifyMagicLink(ctx context.Context, input types.Veri
|
||||
|
||||
email, err := r.iam.AuthService.GetMagicLinkEmail(ctx, input.Token)
|
||||
if err != nil {
|
||||
var errExpiredToken *iam.ErrExpiredToken
|
||||
if errors.As(err, &errExpiredToken) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
var errInvalidToken *iam.ErrInvalidToken
|
||||
if errors.As(err, &errInvalidToken) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
@@ -241,6 +246,11 @@ func (r *mutationResolver) VerifyMagicLink(ctx context.Context, input types.Veri
|
||||
var err error
|
||||
identity, session, continueURL, err = r.iam.AuthService.OpenSessionWithMagicLink(ctx, input.Token)
|
||||
if err != nil {
|
||||
var errExpiredToken *iam.ErrExpiredToken
|
||||
if errors.As(err, &errExpiredToken) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
var errInvalidToken *iam.ErrInvalidToken
|
||||
if errors.As(err, &errInvalidToken) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
@@ -258,6 +268,11 @@ func (r *mutationResolver) VerifyMagicLink(ctx context.Context, input types.Veri
|
||||
var err error
|
||||
identity, session, continueURL, err = r.iam.AuthService.OpenSessionWithMagicLink(ctx, input.Token)
|
||||
if err != nil {
|
||||
var errExpiredToken *iam.ErrExpiredToken
|
||||
if errors.As(err, &errExpiredToken) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
var errInvalidToken *iam.ErrInvalidToken
|
||||
if errors.As(err, &errInvalidToken) {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
|
||||
Reference in New Issue
Block a user