19

I'm trying to develop a REST API web service. I have a question about how to handle user activation email. Currently, the API service handles email sending.

Here is the flow I have at the moment:

  1. User registers via the client application
  2. Client application POSTs to API service
  3. API service validates and adds the user to the database
  4. API service sends the User an activation link
  5. User clicks on the activation link, which will take them to the client application activation page
  6. Client application activation page POSTs to API service
  7. Done

Here is where I currently see the issue:

Because the API service is currently sending the email, the client application does not have control over the look and feel of the email. And there may be URLs in the email that should point to the client application.


Another option is instead of the API service sending the activation email, it will return the activation key to the client application. The client application will then be able to send the activation email to the user.

Two issues I see with this strategy:

  • Security, as the activation key is now exposed to the client application.
  • Not DRY, as each client could be responsible for email sending.

What do you think is best way to handle this?

I would like to allow the client application to customize their email, as well as include client-specific URLs (activation page).

Stephen Watkins
  • 25,047
  • 15
  • 66
  • 100
user742736
  • 2,629
  • 5
  • 30
  • 40
  • 1
    why can't the client send cosmetic information about the email along with the user registration? Also, what platform are you using wherein the client is capable of sending an email? – chiliNUT May 22 '14 at 05:17
  • 1
    It's a Rest API service, So are you saying should accept a json object with html/css to create the email? – user742736 May 22 '14 at 05:26
  • your requirement of "look and feel" are not very specific. if you want the client to control anything about the email, why not just send it to the server as json? – chiliNUT May 22 '14 at 05:27
  • Yes, that's what I mean. send the html/css back as json when the client application POST the registration details – user742736 May 22 '14 at 05:29
  • 1
    I think neither of them should send the email, you can use a messaging queue (like rabbitmq or zeromq) when you add user to database on api side you should add a message to queue with necessary data and a consumer should send the email. You can handle all your project's email needs with a type flag in the message – engvrdr May 22 '14 at 06:06
  • I believe that the REST API web service MUST send the code to user (by email, SMS or other, don't important) skip the client application (REST API web service is independent to client application, they are many) and client application does system to send to REST API web service code. The client can provide an optional parameter who informs the REST API of the method to send code and the Text or HTML to use for send a message, but it's a plus. REST API must send a basic method with only text, for example. – Magicianred Jul 15 '14 at 05:45
  • What abvout the *look and feel* of the email would you like to be customised by the application? It's much better to send emails from your server side than anything else. If there's user data that needs to be added to the email you can do that based on the user requesting activation... – Robert Koritnik Jul 21 '14 at 12:15

8 Answers8

12

TL;DR

Create a small service for developers to create templates, let them declare which template they want to use when POSTing to your activation API


Summary of the problem:

  • e-mail needs to look different for every client app
  • sending mail should be implemented once
  • solution should be secure

There is no need for the e-mail to look different every time. So there's no need to send the e-mail format with the POST request.

Instead one of the following can be done:

1 Create a separate API endpoint to define templates and let the client app choose one of them when POSTing the request for activation.

This is not exactly secure, at least poses a challenge to make it safe if you want to accept HTML from the client apps.

Recommended solution:

2 Create a tool for developers (in the same website where they get their API key) that accepts templates and aids creating them. Client app can choose one of them when POSTing the request for activation. Fragment of the request body being something like:

...
"template": "foobar-app",
"fields": {
    "title": "Welcome to foobar app",
    "username": "jim78"
}
...

No HTML in the fields allowed.

This lets you have pre-defined templates prepared by the developer that can be used by your e-mail sending service and no bug in client app can cause the e-mail to become unsafe. Also, you get a place where the templates can be worked on and tested. (the developer can send them to himself to debug - making e-mail templates is horrible, belive me)

You'll be able to support your developers/clients better in the future and prepare a set of working templates tested in multiple mail clients.

naugtur
  • 16,827
  • 5
  • 70
  • 113
2

A point about security and trust. Typically you send an activation email that contains a url link that has the activation code. The purpose of the email is to validate that the email is valid and that the user has access to that email. The only way the user could have received the verification link is through the email.

If you pass back the activation link to the client then anyone who has access to your API has access to the activation code. If they have access to the link they can bypass the verification process. This is really easy if you have a web app, as they just need to drop into the browser developer mode to see the link. If you have a fat client then they could snoop the network if you are not using encryption like https. They could also, if they were dedicated, decompile your binary (this is why you d not store keys in your binaries).

A backend should never trust a client to implement a security procedure because it never knows when it has been compromised. The safe and correct way is to do the activation email on the server side. Another way to look at this, is that it is similar to the client saying "yes the user is authenticated so give me all the data"

As for the templates there are plenty of good answers above. I would suggest having a catalog of templates and a list of arguments that can be replaced.

2

So the way I achieved this in my opinion is quite a nice way. So I took the methodology of how JSON Web tokens work and applied it to my activation links. I'll explain how it works:

I have 2 web servers, one which handles the REST API, and one which handles the spa.

So the user registers, and the request is sent to the API. The response is then returned to the SPA at which point if successful sends a request to the SPA Backend which signs a token with the user's credentials, the purpose of the token (which is this case is to verify the email address) and it's expiry date.

This token is sent to the user's email address, however on the REST server there is a receiving route that will decode the token and if valid, verifies the email address.

This does mean that technically only 1st party clients can authenticate the email address as they are the only ones that can know your cipher secret. If your secret was freely handed out, then the problem would occur that anyone could verify their email address.

I hope this helps!

EDIT: another way would be to pass a template built in handlebars or something that swaps out variables for actual values. Then have the REST api render it, and email it. (This is probably the best way imo haha)

1

Your API could have an IEmailBodyFormatter object that is passed as a parameter to your API call....

1

I'd extend step 2 with additional post-data sent to the server:

"mail":{
  "placeholder":"someStringChoosenByClientWhichWillBeReplaceByActivationCode",
  "subject":"Hey there, please activate",
  "ishtml":false,
  "body":"SSdtIHRyeWluZyB0byBkZXZlbG9wIGEgUkVTVCBBUEkgd2ViIHNlcnZpY2UuIEkgaGF2ZSBhIHF1ZXN0aW9uIGFib3V0IGhvdyB0byBoYW5kbGUgdXNlciBhY3RpdmF0aW9uIGVtYWlsLiBDdXJyZW50bHksIHRoZSBBUEkgc2VydmljZSBoYW5kbGVzIGVtYWlsIHNlbmRpbmcu"
  "attachments":[
                  {
                     "content-type":"image/png",
                     "filename":"inline_logo.png",
                     "content":"base64_data_of_image"
                  }
                ]
}

This would allow the client full control over sent message, but the activation procedure (mail generation & delivery) is still handled by the service.

Everything except the activation key can be generated for every user by the client (e.g. using "Hello XYZ" as Subject).

I'm not sure whether it's an good idea to allow html-Mails ("ishtml":false,), this depends on your application and the amount of time you want to spent implementing this.

tillz
  • 2,108
  • 15
  • 21
0

Allow the client to manage their own email template(s). When they post a new user registration, allow them to specify which template to use. Then your application is sending the email message, but clients can control what it looks like.

POST /email-templates
{
    "subject": "Complete Your Registration",
    "body": "<html>Follow this link to complete your registration: {activationLink}. It is valid for 45 minutes.</html>"
}

POST /registration-requests
{
    "name": "John Q. Public",
    "emailTemplate": "/email-templates/45"
}
Eric Stein
  • 13,209
  • 3
  • 37
  • 52
  • This seems to have security issues. The service could be used to send people malicious messages. The templates should be defined in a more secure way, preferably along with the process of getting the API key – naugtur Jul 21 '14 at 20:43
  • @naugtur Where is the issue? Only a client can create/modify a template. Clients can only modify or specify templates they can see, which should be locked down to the templates they've created. Assuming the resources are properly secured and checked, I'm missing the issue. – Eric Stein Jul 21 '14 at 20:56
  • In multiple APIs the client app uses a token that maps to a certain user, while the e-mail templates actually have a 1-1 relation with the client app or the client app developer. If the app can define templates, any bug in the app can be exploited to send malicious content. When the e-mail templates are defined outside the client app, they are as secure as the developer's own account she uses to control the API key etc. Also, see my answer. I'm being constructive ;) – naugtur Jul 21 '14 at 21:15
0

I think the proper way is to expose the activation key for the client to do whatever it wants with.

You could also add another endpoint to send the activation key for the user.

Returns user. (with the url like User/{userid} and other resources url like User/{userid}/ActivationKey)

User (POST) 

This can returns the current user and other resources like Email, Activate, etc. For info about the key (like dates, expiration, etc)

User/{userid}/ActivationKey

from there you can extend it as long as you want with :

Preview activation email:

User/{userid}/ActivationKey/Email (GET) 

Update activation email with template, smtp server, etc of the email. :

User/{userid}/ActivationKey/Email (PUT)

Create (and send) activation email, possible with date to send or other send options (text-html versions, etc) :

User/{userid}/ActivationKey/Email (POST)

You could possibly list all email sent and preview them in another endpoint if necessary.

User/{userid}/Emails (GET)
User/{userid}/Emails/{emailid} (GET)
Bart Calixto
  • 19,210
  • 11
  • 78
  • 114
0

I join nauktur on the idea of letting the client send you a template of his email. (And +1 for talking about a way to test, because I agree on the awfulness of mail "development").

But why so complicated ? Client apps mean developers, so why not let them give them your default template (with HTML), let them play around if they want to, and send you back the version they prefer ?
It's not a lot of work for you (just a new field in the client table and a new route), and it gives them a lot of options.

Here is a basic example where we'll be exposing some parameters so that they can play around with the HTML without even having to know them :

  • app.name
  • app.description
  • activation_code
  • user.* registering info

Basic template

{
  title: "Your activation code for %{app.name}",
  body: "<p>Hi, you've been registered on %{app.name}.
    <p>%{app.description}</p>
    <p>Follow <a href="%{activation_code}">this link to confirm your inscription</a>."
}

Register new template

Then the client says : "I prefer to have a more simple mail, but I want his name in it !".
[PUT] /api/email/templates/client_id

{
  title: "Your activation code",
  body: "<p>Hi %{user.fullname}, Follow <a href="%{activation_code}">this link to confirm your inscription</a>."
}

And here you go. Let them play with HTML, it allows way more personalization.
There's no harm in it except for their image on their clients if they mess up, but they're their clients.

Security issues

It was pointed out that attackers could get access to the token of the client app could inject malicious content in the template. First of all, the risk is already so high if the token leaks, that this is the last of your concerns. Still, if you're scared of this, disallowing img tags and making the content of a tags match the href attribute should solve your issue.

Community
  • 1
  • 1
Jerska
  • 11,722
  • 4
  • 35
  • 54
  • token leak is not that high but injecting code on all my marketing emails that all my customer receive is really high. token generally last few hours. also, token is not (in some situations) that hard to get. – Bart Calixto Jul 22 '14 at 16:37
  • Yeah, but since emails already have so many restrictions, talking about injecting code is actually just about 'img' tags and links (well, at least, to me, if I'm unaware of email exploits, feel free to point it out). If you don't want them to have links in it, you can just disallow them too by replacing ` – Jerska Jul 22 '14 at 16:43
  • I think that having a BUY VIAGRA on somesite.com **text** on your emails is a potentially high security concern. It doesn't have to be malicious code. – Bart Calixto Jul 22 '14 at 18:06
  • Well, then yeah, but still, you got the same possible result with the accepted answer. – Jerska Jul 22 '14 at 18:11
  • You cannot edit a template on accepted answer only with it's token. I agree that it can replace the 'allowed fields' which in my opinion can greatly reduce impact and also fields can be validated. Either way, I'm not favoring one or another for security reasons, I just wanted to pointed out that the comment `the risk is already so high if the token leaks, that this is the last of your concerns` is not valid in some circumstances. – Bart Calixto Jul 22 '14 at 18:19