Jump to content

Page accessible with unique one-time access codes

Recommended Posts

Dear PW Community

Let me shout out my question here, I really don't know where to start and hope someone can give me a hint or tell me to resign and go home and cry.

I want to create a subpage that is only accessible to people with unique access codes. It's gonna be an online concert streaming page (thanks Corona!). People who buy tickets through a local ticketing service should be able to access and stream the show with their individual access code. These codes should work only for this person and show. If someone in the «audience» closes and reopens the page, they should get in again, but not their friends who were given the code of course, basically just like in a club with a ticket and a stamp on the wrist.

Now, is there a possibility to achieve that with more or less basic Processwire skills? In my imagination I have a field where I list the given access codes, another two to add start and ending date/time of the show, maybe one for a unique ID/title of the show.

Is there an existing module for something like that? Should I get into the module development field and create that? How?? Haha. Any comments are welcome here.




Share this post

Link to post
Share on other sites

I have built a couple of similar systems, it's actually not that difficult. You don't need a module for it, you can just write out the logic in your PHP template (I prefer to use custom page classes for stuff like this, but the template file will do fine). A good trick to get started is to separate the requirements into individual tasks that you can finish one by one. In your case, I would divide the requirements into the following tasks and questions:

  1. Create a data structure to hold your access codes, i.e. either a field or new template.
  2. (Optional) How and when are codes created? Manually or automated? For example, when a new concert is created in the system, you could generate a number of access codes automatically, or create a code when a reservation comes in.
  3. (Optional) How are codes distributed? For example, you could select a random code (or generate a new one, see above) when a registration comes in and send it in an autoresponse email.
  4. Create an interface for entering your individual code on a concert page, and validate the codes.
  5. Store the authorization (i.e. a valid entered code) so it can only be used by one person.

Then you can think about how to solve those problems using either custom code or the tools that come with ProcessWire. Here are some suggestions:

  1. I usually use a Table field (part of the ProFields module), because it allows you to store a code alongside with information on it (like expiration date, used/available flag, etc) in a single field. I would have one dedicated template for access-protected events (in your case, concerts) and add one Table field to it which holds the codes for this event.
  2. You can solve this with simple hooks. For example, automatically creating a number of access codes when a new concert is created is only a matter of hooking Pages::add. Or if you want to create codes on demand during registration, hook into the relevant part of your registration process to create the codes when needed.
  3. I would build a simple registration form using FormBuilder, which already includes input validation, payments processing and autoresponder. Again, you can use hooks to insert an individual access code into the autoresponse email. You'll want to have a flag in your codes table which keeps track of whether this code has been used or not, to make sure each code can be used only once.
  4. You can do this in PHP directly in the template file:
    1. Check if the user is already authorized for this concert (see below), and if so, display the concert's content / stream / whatever.
    2. If the user is NOT authorized, display a form for entering the access code.
    3. If a code was submitted, check if the code is valid (i.e. it exists on this page, has not been activated yet — this should be a separate flag in your Table field — etc). If it is, store the authorization for this user (see below) and display the concerts content.
  5. You can use multiple approaches for this, depending on how serious you are about preventing misuse.
    1. A simple approach would be to store the authorization in a cookie or session. This would allow the same user to close and reopen the page (though using the session would mean the codes only stay active for the current browser session). This is pretty simple, but of course has it's limitations. For example, what if users want to switch from the desktop to a mobile phone? Distinguishing between one user switching devices and multiple users sharing an access code will be difficult.
    2. Another possibility is to user ProcessWire user accounts, requiring users to create an account and then adding the authorization for individual concerts to their account directly. Using accounts you could make access codes obsolete entirely. Of course, you'll have to find a solution against account sharing (I'm not sure if ProcessWire allows multiple simultaneous sessions for one account by default).
    3. Note that none of those solutions stop a really determined bad actor from sharing their access to your concerts, or the content you provide. The only solutions for this is to integrate DRM, which is really difficult and not really feasible for small websites. But both the solutions above should work mostly fine.

Ok this text got longer than I intended, and I know it's not a complete solution. But you see the point – by breaking down the requirements into individual parts the system becomes much easier to build. You can pick and choose from existing solutions (ProcessWire user accounts, the FormBuilder and ProFields module, etc) and combine them with custom logic using hooks or the template file. The rest is just a matter of experience with ProcessWire and PHP. If you get stuck on coding specific steps of this system, make sure to post them here, there's always a good solution!

  • Like 8

Share this post

Link to post
Share on other sites

Thank you so much Moritz.

This is even longer than I expected 😄 It sounds like the perfect solution for this and will definitely be my long-term goal – maybe even with the possibility to restrict the visitors location to a country or region.

I know and use the modules you mentioned, on the other hand – please don't laugh – I've never worked with hooks yet. This is new and I'll need some time to try that 😕. One thing got missing here and this probably makes it even simpler. The ticket codes come from an official ticket service where people buy real tickets for real concerts. So for this I won't have to generate codes on request/order and handle payments. So I will (or my customer) most likely have to import or copy/paste these codes. I have to check but I think the gag would be to enter the «online concert venue» with only a code and without a user account or name/password. So I will have to try to store the code along with the visitors IP address in the codes table.

I will get back here and post my solution or further steps or questions.

  • Like 1

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By humanafterall
      I would like to set an admin template to 'https only' as recommended in the Processwire security docs.
      However if I do this it forces this setting locally too, resulting in https://localhost requests which result in an error page.
      Is there a simple way round this? Setting https for templates in the config?
    • By theoretic
      Hi guys and ladies! And thanks for Processwire!
      It appears i've got an interesting issue concerning the template-settings-based PW redirects dealing with access control. Any PW template has some access control options i.e. "Login redirect URL or page ID to render". If this option is used for a page having a template with this option filled, a redirect will occur if user is not logged in and/or has insufficient access rights.
      I like to hook PW events. In one of my current projects i decided to write an addHookBefore('Session::redirect', ...) which should store the page we are being redirected from. With "regular" redirects like $session->redirect('/somewhere/') this hook works like a charm. But it was strange to see that it doesn't work with the template-settings-based redirect.
      I'm too dumb to dive deep inside PW and to examine the whole PW session mechanism. But it could be rather logical if ANY redirect ( no matter template-settings-based or using $session->redirect() ) could be hooked in the same manner.
      Okay okay i can forget about template-settings-based redirect and write my own. Just a couple of lines of code, and it works. But it's less elegant than hooking the template-settings-based redirects.
      So am i missing something? It this behavior a bug, or is it intended by PW team? Thanks in advance for any comment!
    • By Guy Incognito
      What's the best process for adding another user with TfaTotp 2FA? Just using it for the first time.
      Should I supply them with them with the secret when I first create their account? Seems like a security risk?
      Otherwise how do I create a 2FA user and let them login for the first time?
    • By Chris Bennett
      Plenty of posts on the forum relating to Content Security Policy (CSP) and how to integrate it with Processwire.
      It's not too hard to implement a decent htaccess CSP that will get you a solid B+ at Mozilla Observatory.
      If you're after A+ it's a little harder because of all the back-end stuff... until you realize it's surprisingly easy.
      After a lot of testing, the easiest way I found was to specify only what is needed in the htaccess and then add your required CSP as a meta in your page template.
      Plenty of people have suggested similar. Works very easily for back-end vs front-end, but gets complicated if you want front page editing.
      Luckily, a little php will preserve back-end and front page editing capabilities while allowing you to lock down the site for anyone not logged in. 
      None of this is rocket science, but CSPs are a bit of a pain the rear, so the easier the better, I reckon 😉
      The only CSP I'd suggest you include in your site htaccess is:
      Header set Content-Security-Policy "frame-ancestors 'self'" The reason for this is you can't set "frame-ancestors" via meta tags.
      In addition, you can only make your CSP more restrictive using meta tags, not less, so leaving the back-end free is a solid plan to avoid frustration.
      Then in your public front-facing page template/s, add your desired Content Security Policy as a meta tag.
      Please note: your CSP should be the first meta tag after your <head>.

      For example:
      <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Security-Policy" content="Your CSP goes here"> <!-- followed by whatever your normal meta tags are --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="format-detection" content="telephone=no"> If you haven't got Front Page Editing enabled, this works fine by itself.
      Just one extra step is needed to make sure you don't have to worry either way. 
      The easiest way I found to allow both CSP and front page editing capabilities is the addition of a little php, according to whatever your needs are.
      Basically, if the user is a guest, throw in your CSP, if they're not do nothing.
      It's so simple I could have kicked myself when it finally dawned on me.
      I wish it had clicked for me earlier in my testing, but it didn't so I'm here to try to save some other person a little time.
      <!DOCTYPE html> <html> <head> <?php if ($user->isGuest()): ?> <meta http-equiv="Content-Security-Policy" content="Your CSP goes here"> <?php endif; ?> <!-- followed by whatever your normal meta tags are --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="format-detection" content="telephone=no">  
      If you want it a bit more involved then you can add additional tests and be as specific as you like about what pages should get which CSP.
      For example, the following is what I use to expand the scope of the CSP only for my "map" page:
      <?php $loadMap = $page->name === "map"; ?> <!DOCTYPE html> <html> <head> <?php if ($user->isGuest()): ?> <meta http-equiv="Content-Security-Policy" content="default-src 'none'; base-uri 'self'; manifest-src 'self'; form-action 'self'; font-src 'self' data: https://fonts.gstatic.com; frame-src 'self' https://www.youtube.com; img-src 'self' data:<?php echo ($loadMap) ? " https://maps.googleapis.com https://maps.gstatic.com" : ""; ?> https://www.google-analytics.com; script-src 'self' <?php echo ($loadMap) ? "https://maps.googleapis.com " : ""; ?>https://www.google-analytics.com https://www.googletagmanager.com; style-src 'self' <?php echo ($loadMap) ? "'unsafe-inline' https://fonts.googleapis.com" : ""; ?>"> <?php endif; ?>  Hope this saves someone a little time testing.
    • By VeiJari
      Hello forum, this is my first security related post, so I'm a bit of a newbie.
      I understand that when I have direct front-input from user I should sanitize the input, but how about when I use a secret key for showing a API for a third-party supplier? Should I sanitize the input->get() key?
      I've tested this issue and I tried ?key=<?php echo $page->field; ?> And without adding any sanitization it comes back: /?key=<?php%20echo%20$page->field;%20?>
      So can I rely on this, or should I still use $sanitizer just in case?
      Thanks for the help!
  • Create New...