1

Our sports site is unlocking one of its main services so it is no longer necessary to sign up to use it for a few days. Anonymous users would have access for a few days, then we would lock them out and prompt them to sign up.

I figured out a way to implement this, other than using the session information (like a cart), a randomly generated token would be given to the user and passed through the URL would grant access, e.g. example.org/service/<service_id>?token=xxxxxxxxxxxxxx. On our backend we would store the token granting access to that service_id and keep information like an expiration date.

The token value (is there a better term than "value" for tokens?) would be generated through random bytes and base64-encoded so that it is URL safe:

base64.b64encode(os.urandom(30))

Please let me know if this is a good method of generating a random and safe token.

I guess a similar method would be this, although not exactly 30 bytes, but 30 characters:

"".join([random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(30)]

When asking about this on Python/Django communities I was suggested pyjwt, which is for JSON Web Tokens. But I fail to see how to use it or how web tokens come into my scenario.

  • would I be encoding the randomly generated token as payload? But that would result in encoding something twice, it doesn't seem necessary.

  • it supports encoding the token with expiration, but I would be storing that in our backend anyway and is easy to handle

Perhaps I am overcomplicating this, but I would like to know if there is a conventional way of designing such access token architectures.

2
  • You are aware that users whose token expired could go back to the page where you provide a free token to have access for N more days, right?
    – Ángel
    Mar 8 at 20:26
  • I will spare the details of how our services work but no, the situation you describe wouldn't be possible.
    – dabadaba
    Mar 9 at 8:24

2 Answers 2

0

It doesn't seem necessary that you encode the token, especially in your case, since it would result to encode something twice.

You should instead focus on encrypting it, i.e. avoiding transmitting it over non-HTTPS connections. Oherwise anyone with access to a network might steal the token of a user.

1
  • Could you please expand on this? How would the token be stolen? (technically anybody with the URL would have access to the service and that's tecnically ok, although I intend on restricting access to 1 unique browser session per service so they don't share it with others). And what would be the actual measures to take?
    – dabadaba
    Mar 8 at 15:09
0

(This isn't really a security question; you're not asking about any user input and thus not asking about an avenue for attack.)

"Proper" base64 is not actually URL-safe; it can contain three different characters (+, /, and =) that have special meanings in URLs. You should either use a URL-safe base64 encoding (which typically replaces + and / with URL-safe symbols, and omits the = padding characters), or use a different encoding such as hex (base16).

Alternatively, rather than using a URL parameter, have the page that issues the token make the browser POST that token to the other server, or submit the token in a header, or submit the token in a cookie. Cookies have some character restrictions, but often your web framework will take care of those for you. Header values can have almost anything except newlines. URL bodies can be in any format you want (though unless you submit as plain text / binary, you probably do want to encode the token as something).

A cookie is almost certainly the most straightforward, especially if the token should be sent on every request to that site; this is exactly what cookies are meant for. The cookie would store your value, an authorization and (anonymous) session token, and submit it automatically until either the cookie expired or the site removed it. This does require that the token-issuing site and the destination site are on a common domain, though.

Submitting in a header requires using JS to trigger the request (and means it can't be done for navigation requests), but many sites do this anyway to load content using front-end frameworks. It works across domains, assuming you have configured CORS to allow this.

Submitting in a POST body can only be done using JS requests or by submitting an HTML form (though the latter can be done automatically and invisibly to the user, via script). It is generally preferred over URL parameters for sensitive fields, because URLs are much more likely to be logged on servers, browsers, and proxies and you don't want sensitive values in logs. However, if the value is not sensitive (because it's anonymous, available to any user, and not tied to any user-specific info/activity) then using URL parameters instead is fine.

3
  • The token needs to be in the URL. It's the whole point, so that you can copy the URL and have access to the same page in a different browser/device or share it.
    – dabadaba
    Apr 11 at 10:31
  • Ah you didn't mention in the question that the token is supposed to be shared! Usually that is the exact opposite of something you want for a token! I'm kind of confused what the point of such a token would even be; if it's not tied to a user/device, why not just allow access directly without needing any token at all? What is the point of such an anonymous, publicly shared token? (Feel free to edit this into the question, it's probably relevant for everybody.)
    – CBHacking
    Apr 12 at 6:56
  • I don't want to ramble on the details of why it's necessary. It's a temporary token giving trial access to a page, but we don't want anybody accessing that page because there's a sense of "ownership" for the product we're showing. Only the original anonymous user can view it in any device or whoever they decide to share it with (limited to a number of different sessions).
    – dabadaba
    Apr 12 at 8:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .