{"id":131669,"date":"2023-02-06T18:12:49","date_gmt":"2023-02-06T18:12:49","guid":{"rendered":"https:\/\/blog.finxter.com\/?p=1113906"},"modified":"2023-02-06T18:12:49","modified_gmt":"2023-02-06T18:12:49","slug":"i-made-a-password-generator-in-streamlit-thats-really-secure-maybe-too-secure","status":"publish","type":"post","link":"https:\/\/sickgaming.net\/blog\/2023\/02\/06\/i-made-a-password-generator-in-streamlit-thats-really-secure-maybe-too-secure\/","title":{"rendered":"I Made a Password Generator in Streamlit That\u2019s Really Secure (Maybe Too Secure!)"},"content":{"rendered":"\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-top\" data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;1113906&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;top&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;1&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\\\/5 - (1 vote)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;width&quot;:&quot;142.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n<div class=\"kksr-stars\">\n<div class=\"kksr-stars-inactive\">\n<div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"kksr-stars-active\" style=\"width: 142.5px;\">\n<div class=\"kksr-star\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<div class=\"kksr-star\" style=\"padding-right: 5px\">\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/div>\n<div class=\"kksr-legend\" style=\"font-size: 19.2px;\"> 5\/5 &#8211; (1 vote) <\/div>\n<\/p><\/div>\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube\"><a href=\"https:\/\/blog.finxter.com\/how-i-created-a-secure-password-and-passphrase-generator-in-streamlit\/\"><img decoding=\"async\" src=\"https:\/\/blog.finxter.com\/wp-content\/plugins\/wp-youtube-lyte\/lyteCache.php?origThumbUrl=https%3A%2F%2Fi.ytimg.com%2Fvi%2FMxm3l3uDpFA%2Fhqdefault.jpg\" alt=\"YouTube Video\"><\/a><figcaption><\/figcaption><\/figure>\n<h2>Project Description<\/h2>\n<p>Both in my day job and personal life, I notice every day how important online security has become. Almost every part of our everyday lives are connected somehow to the Internet. And everyone of those connections requires (or should need) a password at the least. <\/p>\n<p>The problem with that is that passwords are often difficult to remember if you want to make them secure. Furthermore, it is difficult to randomize them when we create them. <\/p>\n<p>People think in patterns, and I am no different. <\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/shandralor-streamlit-password-generator-app-dzbr8y.streamlit.app\/\" target=\"_blank\" rel=\"noreferrer noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"561\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-73-1024x561.png\" alt=\"\" class=\"wp-image-1113997\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-73-1024x561.png 1024w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-73-300x164.png 300w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-73-768x421.png 768w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-73-1536x842.png 1536w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-73.png 1614w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\"><a href=\"https:\/\/shandralor-streamlit-password-generator-app-dzbr8y.streamlit.app\/\" data-type=\"URL\" data-id=\"https:\/\/shandralor-streamlit-password-generator-app-dzbr8y.streamlit.app\/\" target=\"_blank\" rel=\"noreferrer noopener\">PW Generator App Live Demo<\/a><\/figcaption><\/figure>\n<\/div>\n<p>To solve this, I use a self-hosted password manager, but this is not an easy thing to set up. To bridge the gap between how most people look at passwords these days and the ideal way of keeping them, I developed a simple web application. <\/p>\n<p>It uses my favorite framework <a href=\"https:\/\/blog.finxter.com\/how-i-built-a-house-price-prediction-app-using-streamlit\/\" data-type=\"post\" data-id=\"1104457\" target=\"_blank\" rel=\"noreferrer noopener\">Streamlit<\/a>, and should not take you more than half an hour to create. Let\u2019s jump in!<\/p>\n<h2>Install dependencies<\/h2>\n<p>The first thing I\u2019ll do every time is installing all the needed dependencies. <\/p>\n<p>For this project, we will need the Streamlit library, as well as <code>Random_Word<\/code> and <code><a rel=\"noreferrer noopener\" href=\"https:\/\/blog.finxter.com\/python-requests-library\/\" data-type=\"post\" data-id=\"37796\" target=\"_blank\">requests<\/a><\/code>. <\/p>\n<p>As with my other tutorials, I will explain why we need these as we encounter them in our code.<\/p>\n<pre class=\"wp-block-preformatted\"><code>pip install streamlit\npip install Random_Word\npip install requests<\/code><\/pre>\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n<h2>Step 1: Set up the directory structure<\/h2>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"693\" height=\"457\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-75.png\" alt=\"\" class=\"wp-image-1114002\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-75.png 693w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-75-300x198.png 300w\" sizes=\"auto, (max-width: 693px) 100vw, 693px\" \/><\/figure>\n<\/div>\n<p>I use VS Code as my editor of choice, and setting up a new project folder there is a breeze. <\/p>\n<p>Right-click in the Explorer menu on the left side and click <code>New Folder<\/code>. We only need one folder, <code>.streamlit<\/code>, to hold our Streamlit <code>config.toml<\/code> and <code>secrets.toml<\/code> files. <\/p>\n<p>We will write all our code in a single <code>app.py<\/code> file.<\/p>\n<pre class=\"wp-block-preformatted\"><code>\u251c\u2500\u2500 .streamlit\n\u2502 \u251c\u2500\u2500 config.toml\n\u2502 \u2514\u2500\u2500 secrets.toml\n|\u2500\u2500 app.py<\/code>\n<\/pre>\n<h2>Step 2: Getting the API Ninja API key<\/h2>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"690\" height=\"457\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-76.png\" alt=\"\" class=\"wp-image-1114003\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-76.png 690w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-76-300x199.png 300w\" sizes=\"auto, (max-width: 690px) 100vw, 690px\" \/><\/figure>\n<\/div>\n<p>For the passphrase aspect of our application, we\u2019ll need an API key to get us random words. I used the API Ninja Random Word API, which you can find <a href=\"https:\/\/api-ninjas.com\/api\/randomword\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>. Signing up for their service is quick, easy and, most importantly, free! <\/p>\n<p>Navigate to their <a href=\"https:\/\/api-ninjas.com\/register\" target=\"_blank\" rel=\"noreferrer noopener\">registration page<\/a> and follow the sign-up procedure.\u00a0<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"702\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-68-1024x702.png\" alt=\"\" class=\"wp-image-1113917\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-68-1024x702.png 1024w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-68-300x206.png 300w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-68-768x527.png 768w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-68-1536x1053.png 1536w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-68.png 1600w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n<p>Afterward, you should be able to create your API key and get started right away. Your screen should look something like this, except for the API calls. Yours will be zero when you start this for the first time.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"574\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-69-1024x574.png\" alt=\"\" class=\"wp-image-1113918\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-69-1024x574.png 1024w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-69-300x168.png 300w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-69-768x431.png 768w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-69-1536x861.png 1536w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-69.png 1600w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n<p>Once you\u2019ve grabbed your API key, navigate back to your folder structure and create a variable in the <code>secrets.toml<\/code> file. Paste your key on the right side of the <code>=<\/code> sign, and you\u2019re ready to start coding!<\/p>\n<p class=\"has-global-color-8-background-color has-background\"><em><strong>Tip<\/strong>: Don\u2019t forget the quotes <img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f642.png\" alt=\"\ud83d\ude42\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/em><\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"282\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-70-1024x282.png\" alt=\"\" class=\"wp-image-1113919\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-70-1024x282.png 1024w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-70-300x83.png 300w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-70-768x211.png 768w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-70-1536x423.png 1536w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-70.png 1552w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n<h2>Step 3: Import dependencies and Streamlit basic set-up<\/h2>\n<p>At the top of our file, we first import all the dependencies for our app to function. These are the three packages we installed earlier, as well as the <code>secrets<\/code><em> <\/em>and <code>string<\/code> modules that come built-in to Python. <\/p>\n<p>These I will use to generate an, as close to possible, random password.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#---PIP PACKAGES----#\nimport streamlit as st\nfrom random_word import ApiNinjas\nimport requests #---BUILT IN PYTHON PACKAGES----#\nimport secrets\nimport string<\/pre>\n<p>When building Streamlit applications, I find it easiest to first get their initial configuration done quickly, so I don\u2019t have to worry about it later. <\/p>\n<p>The first thing to do is define a couple of parameters we will need to initialize our application. That way, we can change them later if we are so inclined. <\/p>\n<p>I do this in the\u00a0 <code>#---STREAMLIT SETTINGS---#<\/code> block.\u00a0<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#---STREAMLIT SETTINGS---#\npage_title = \"PW &amp; PW-Sentence Generator\"\npage_icon = \":building_construction:\"\nlayout = \"centered\"<\/pre>\n<p>The first function you will always need to call to get your Streamlit app to function is <code>st.set_page_config()<\/code>. If you forget this, Streamlit will get annoyed and start throwing errors.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#---PAGE CONFIG---#\nst.set_page_config(page_title=page_title, page_icon=page_icon, layout=layout) \"#\"\nst.title(f\"{page_icon} {page_title}\") \"#\"\n<\/pre>\n<p>The last block, <code>#---STREAMLIT CONFIG HIDE---#<\/code>, is optional but hides the <strong>\u201cMade with Streamlit\u201d<\/strong> banner at the bottom and the hamburger menu at the top if you want to.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#---STREAMLIT CONFIG HIDE---#\nhide_st_style = \"\"\"&lt;style> #MainMenu {visibility : hidden;} footer {visibility : hidden;} header {visibility : hidden;} &lt;\/style> \"\"\"\nst.markdown(hide_st_style, unsafe_allow_html=True)<\/pre>\n<p>When you\u2019ve inserted all the code above and then called the command below, a browser window should open.\u00a0<\/p>\n<p class=\"has-global-color-8-background-color has-background\"><img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f449.png\" alt=\"\ud83d\udc49\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/> <em><strong>Tip<\/strong>: Make sure you run the command in the root of your application folder!<\/em><\/p>\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">streamlit run app.py<\/pre>\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n<p>After a few seconds and your view should resemble the one below<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"651\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-71-1024x651.png\" alt=\"\" class=\"wp-image-1113978\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-71-1024x651.png 1024w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-71-300x191.png 300w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-71-768x488.png 768w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-71.png 1465w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n<p>At this point, I usually let the application run in the background. This allows me to see all my changes to the code in semi-real-time on the browser window.&nbsp;<\/p>\n<h2>Step 3: Defining our password generator function<\/h2>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"691\" height=\"456\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-77.png\" alt=\"\" class=\"wp-image-1114004\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-77.png 691w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-77-300x198.png 300w\" sizes=\"auto, (max-width: 691px) 100vw, 691px\" \/><\/figure>\n<\/div>\n<p>The idea for the app is to have the ability for a user to choose if he wants a secure password or a secure passphrase. For this to work, we need functions that can generate those passwords or passphrases. <\/p>\n<p>The current length for a secure password is between 14 and 16 randomized characters. I use a length of 14 for my function but you can change this very easily.\u00a0<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#---PW GENERATOR FUNCTION--#\ndef generate_pw()->None: \"\"\"Uses the string module to get the letters and digits that make up the alphabet used to generate the random characters. These characters are appended to the pwd string which is then assigned to the session_state variable [pw]\"\"\" letters = string.ascii_letters digits = string.digits alphabet = letters + digits pwd_length = 14 pwd = '' for i in range(pwd_length): pwd += ''.join(secrets.choice(alphabet)) st.session_state[\"pw\"] = pwd\n<\/pre>\n<p>This function first creates the <code>letters<\/code> and <code>digits<\/code> variables using the methods from the Python <code>string<\/code> module we imported earlier. These are then <a rel=\"noreferrer noopener\" href=\"https:\/\/blog.finxter.com\/daily-python-puzzle-string-concatenation\/\" data-type=\"post\" data-id=\"93\" target=\"_blank\">concatenated<\/a> into one long string we call <code>alphabet<\/code>. <\/p>\n<p>Next, I set the preferred password length at 14 characters. Feel free to change this.<\/p>\n<p>The actual password generation occurs next. We concatenate random characters from this <code>alphabet<\/code> variable to the initially empty <code>pwd<\/code> variable.<\/p>\n<p>According to the <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.python.org\/3\/library\/secrets.html\" target=\"_blank\">official documentation<\/a> of the secrets module, \u201c<em>the<\/em><a href=\"https:\/\/docs.python.org\/3\/library\/secrets.html#module-secrets\"><em> <\/em><\/a><em>secrets module provides access to the most secure source of randomness that your operating system provides\u201d<\/em>. <\/p>\n<p>In other words, it comes as close to random as possible <img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f642.png\" alt=\"\ud83d\ude42\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/p>\n<p>The last thing we need to do is to assign the completed password to the <code>st.session_state[\"pw\"]<\/code> variable. The <code>st_session_state<\/code> is, in essence, a <a href=\"https:\/\/blog.finxter.com\/python-dictionary\/\" data-type=\"post\" data-id=\"5232\" target=\"_blank\" rel=\"noreferrer noopener\">dictionary<\/a>. This dictionary is accessible by the Streamlit application during the entire time it is running. It allows passing variables, states to different parts of your app at different times. <\/p>\n<p>In our case, we will use it to store the generated value of both the password and passphrase.<\/p>\n<h2>Step 4: Defining our passphrase generator functions<\/h2>\n<p>For generating the passphrase, I found that I needed two functions. It is possible to do it in one function, of course, but I found it a lot tidier to split it up. <\/p>\n<p>It also seems more Pythonic to me, as it adheres to the tenet that every function should only do one thing.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#---PASSPHRASE GENERATOR FUNCTIONS---# #---GET RANDOM WORD---#\ndef get_random_word()->str: \"\"\"Uses the API Ninja API to request a word string. This string is then parsed to extract only the word and return it.\"\"\" api_url = 'https:\/\/api.api-ninjas.com\/v1\/randomword' response = requests.get(api_url, headers={'X-Api-Key': st.secrets.API_NINJA}) if response.status_code == requests.codes.ok: returned_word = response.text.split(\":\") returned_word = returned_word[1] returned_word = returned_word[2:-2] return returned_word else: return \"Error:\", response.status_code, response.text<\/pre>\n<p>The first function, <code>get_random_word()<\/code> will use the API Ninja API to request and return a random word. For this, we need to call the API Key we stored earlier. <\/p>\n<p>Streamlit has a secure method for this using the <code>st.secrets<\/code> method. We just add a <code>.<\/code> and then the name of the key we defined in the <code>secrets.toml<\/code> file. That way, we never expose the actual key.<\/p>\n<p>The returned string has some extra characters attached to it that we need to strip off. We only need the actual word for our purpose. If something goes wrong with the request our else statement will trigger. This will return the error code and message.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> #---GENERATING THE PHRASE---#\ndef generate_ps()->None: \"\"\"Uses the get_random_word function to request five words. These are concatenated into a string with dashes and then assigned these to the session_state variable [pw] \"\"\" passphrase = \"\" for x in range(5): passphrase += f\"{get_random_word()}-\" passphrase_final = passphrase[:-1] st.session_state[\"pw\"] = passphrase_final<\/pre>\n<p>Our second function will create the actual passphrase we need. As with the password, you can choose the length for yourself. I set the length for mine at 5 words, which should be more than secure enough.&nbsp;<\/p>\n<p>To start, we define an empty string <code>passphrase<\/code>. Then we will call the <code>get_random_word()<\/code> function for the length I mentioned above. This will get us the number of words we need. <\/p>\n<p>For each iteration of our loop, I concatenate the received words + a dash to the passphrase string. For that I use my favorite formatting method for Python strings, the <strong><a rel=\"noreferrer noopener\" href=\"https:\/\/blog.finxter.com\/string-formatting-vs-format-vs-formatted-string-literal\/\" data-type=\"post\" data-id=\"13190\" target=\"_blank\">f-string<\/a><\/strong>. When we\u2019ve added all the words and dashes to the passphrase, we strip off the last dash.<\/p>\n<p>The last thing we need to do here is to also assign the generated string to the <code>st.session_state[\"pw\"]<\/code> variable.\u00a0 This is the same thing we did with the password.<\/p>\n<h2>Step 5: Creating the Streamlit application<\/h2>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"693\" height=\"461\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-78.png\" alt=\"\" class=\"wp-image-1114005\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-78.png 693w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-78-300x200.png 300w\" sizes=\"auto, (max-width: 693px) 100vw, 693px\" \/><\/figure>\n<\/div>\n<p>For the UI aspect of our application, we only need a few lines of code, most of them related to the layout.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#---MAIN PAGE---# if \"pw\" not in st.session_state: st.session_state[\"pw\"] = '' \"---\"\n<\/pre>\n<p>The first part is ensuring the <code>st.session_state[\"pw\"]<\/code> gets initialized. <\/p>\n<p>We assign it to an <a href=\"https:\/\/blog.finxter.com\/python-create-list-of-n-empty-strings\/\" data-type=\"post\" data-id=\"455008\" target=\"_blank\" rel=\"noreferrer noopener\">empty string<\/a> to prevent Streamlit from throwing an error. The 3 dashes between quotes are part of Streamlit\u2019s magic commands. It will insert a horizontal divider in our application without any complicated code.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">col1,col2 = st.columns([4,4], gap = \"large\") with col1: st.caption(\"Secure password length is set at 14 chars.\") st.button(\"Generate secure password\", key = \"pw_button\", on_click = generate_pw) with col2: st.caption(\"Secure passphrase length is set at 5 words.\") st.button(\"Generate secure password sentence\", key = \"ps_button\", on_click = generate_ps) \"#\"\n<\/pre>\n<p>As we are allowing the user to choose between creating a password or a passphrase, we\u2019ll need two columns to display these. <\/p>\n<p>When calling <code>st.columns<\/code> with more than one argument, the width of each column needs to be in a <a href=\"https:\/\/blog.finxter.com\/python-lists\/\" data-type=\"post\" data-id=\"7332\" target=\"_blank\" rel=\"noreferrer noopener\">list<\/a>. That list will then function as the first argument. The <code>gap<\/code> keyword provides a relative vertical separation between the columns.<\/p>\n<p>Defining the content for each column is easily done. We create a <code>with<\/code>-statement for each of the columns. All the code inside the statement then becomes part of that column.\u00a0<\/p>\n<p>The <code>st.caption<\/code> method allows us to provide a hint or extra info. In my case, I use it to tell the user about the current length of the password or passphrase. <\/p>\n<p>The second part of every column is the button used to generate our password\/passphrase. <\/p>\n<p class=\"has-base-background-color has-background\"><img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f449.png\" alt=\"\ud83d\udc49\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/> <strong>Recommended<\/strong>: <a href=\"https:\/\/blog.finxter.com\/learning-streamlits-buttons-features\/\" data-type=\"post\" data-id=\"462652\" target=\"_blank\" rel=\"noreferrer noopener\">Streamlit Button &#8211; Ultimate Guide with Video<\/a><\/p>\n<p>Streamlit\u2019s <code>st.button()<\/code> method as a simple <code>on_click<\/code> keyword argument. You can pass a function to it that gets run when the button gets clicked.\u00a0<\/p>\n<p>At the bottom, we use another bit of Streamlit magic. The <em>\u201c<\/em><code>#<\/code><em>\u201d <\/em>will insert a horizontal space\/new line to create some separation.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\"#\"\nocol1, ocol2, ocol3 = st.columns([1,4,1])\nwith ocol1: ''\nwith ocol2: st.caption(\"Generated secure PW\") \"---\" st.subheader(st.session_state[\"pw\"]) \"---\" with ocol3: ''<\/pre>\n<p>The very last part of our application is more layout. <\/p>\n<p>I define three columns to center the generated password. We can add the empty string to the first and third columns. These strings are once again part of Streamlit magic. The middle column will hold our generated password\/passphrase. <\/p>\n<p>Showing the password is easy. Because we\u2019ve assigned the generated values to the <code>st.session_state[\"pw\"]<\/code> variable, we can just call it.<\/p>\n<h2>Step 6: Putting it all together<\/h2>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"694\" height=\"460\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-79.png\" alt=\"\" class=\"wp-image-1114010\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-79.png 694w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-79-300x199.png 300w\" sizes=\"auto, (max-width: 694px) 100vw, 694px\" \/><\/figure>\n<\/div>\n<p>If everything went well your completed code will look similar to my code below.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#---PIP PACKAGES----#\nimport streamlit as st\nfrom random_word import ApiNinjas\nimport requests #---BUILT IN PYTHON PACKAGES----#\nimport secrets\nimport string #---STREAMLIT SETTINGS---#\npage_title = \"PW &amp; PW-Sentence Generator\"\npage_icon = \":building_construction:\"\nlayout = \"centered\" #---PAGE CONFIG---#\nst.set_page_config(page_title=page_title, page_icon=page_icon, layout=layout) \"#\"\nst.title(f\"{page_icon} {page_title}\") \"#\" #---STREAMLIT CONFIG HIDE---#\nhide_st_style = \"\"\"&lt;style> #MainMenu {visibility : hidden;} footer {visibility : hidden;} header {visibility : hidden;} &lt;\/style> \"\"\"\nst.markdown(hide_st_style, unsafe_allow_html=True) #---PW GENERATOR FUNCTION--#\ndef generate_pw()->None: \"\"\"Uses the string module to get the letters and digits that make up the alphabet used to generate the random characters. These characters are appended to the pwd string which is then assigned to the session_state variable [pw]\"\"\" letters = string.ascii_letters digits = string.digits alphabet = letters + digits pwd_length = 14 pwd = '' for i in range(pwd_length): pwd += ''.join(secrets.choice(alphabet)) st.session_state[\"pw\"] = pwd #---PASSPHRASE GENERATOR FUNCTIONS---# #---GET RANDOM WORD---#\ndef get_random_word()->str: \"\"\"Uses the API Ninja API to request a word string. This string is then parsed to extract only the word and return it.\"\"\" api_url = 'https:\/\/api.api-ninjas.com\/v1\/randomword' response = requests.get(api_url, headers={'X-Api-Key': st.secrets.API_NINJA}) if response.status_code == requests.codes.ok: returned_word = response.text.split(\":\") returned_word = returned_word[1] returned_word = returned_word[2:-2] return returned_word else: return \"Error:\", response.status_code, response.text #---GENERATING THE PHRASE---#\ndef generate_ps()->None: \"\"\"Uses the get_random_word function to request five words. These are concatenated into a string with dashes and then assigned these to the session_state variable [pw] \"\"\" passphrase = \"\" for x in range(5): passphrase += f\"{get_random_word()}-\" passphrase_final = passphrase[:-1] st.session_state[\"pw\"] = passphrase_final #---MAIN PAGE---# if \"pw\" not in st.session_state: st.session_state[\"pw\"] = '' \"---\"\ncol1,col2 = st.columns([4,4], gap = \"large\") with col1: st.caption(\"Secure password length is set at 14 chars.\") st.button(\"Generate secure password\", key = \"pw_button\", on_click = generate_pw) with col2: st.caption(\"Secure passphrase length is set at 5 words.\") st.button(\"Generate secure password sentence\", key = \"ps_button\", on_click = generate_ps) \"#\" \"#\"\nocol1, ocol2, ocol3 = st.columns([1,4,1])\nwith ocol1: ''\nwith ocol2: st.caption(\"Generated secure PW\") \"---\" st.subheader(st.session_state[\"pw\"]) \"---\" with ocol3: ''\n<\/pre>\n<p>When you check the browser again, your application should be ready to use!<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"920\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-72-1024x920.png\" alt=\"\" class=\"wp-image-1113996\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-72-1024x920.png 1024w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-72-300x269.png 300w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-72-768x690.png 768w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-72.png 1041w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n<p class=\"has-base-background-color has-background\"><em><strong>Tip<\/strong>: When pressing the passphrase button, a slight delay might occur as the app contacts the API <img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f642.png\" alt=\"\ud83d\ude42\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/em><\/p>\n<h2>Conclusion<\/h2>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"688\" height=\"457\" src=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-80.png\" alt=\"\" class=\"wp-image-1114013\" srcset=\"https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-80.png 688w, https:\/\/blog.finxter.com\/wp-content\/uploads\/2023\/02\/image-80-300x199.png 300w\" sizes=\"auto, (max-width: 688px) 100vw, 688px\" \/><\/figure>\n<\/div>\n<p>I hope you liked this tutorial. It is very basic in its functionality, but the potential for a lot more is there. <\/p>\n<p>I have some ideas of my own that I would like to implement. Chief among them is the ability to choose the number of characters or words for the password\/passphrase. <\/p>\n<p>Another one, but this will be a separate project, is to create a mobile app version of this. Who knows, you might see it here if I succeed.\u00a0<\/p>\n<p>Have fun building this!<\/p>\n<ul>\n<li><a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/finxter\/Streamlit-Password-Generator\" data-type=\"URL\" data-id=\"https:\/\/github.com\/finxter\/Streamlit-Password-Generator\" target=\"_blank\">You can find the Github for this project here.<\/a><\/li>\n<li>Feel free to <a rel=\"noreferrer noopener\" href=\"https:\/\/teckhawk.streamlit.app\/\" target=\"_blank\">contact me<\/a> with questions or suggestions <img decoding=\"async\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/1f642.png\" alt=\"\ud83d\ude42\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/li>\n<li><a href=\"https:\/\/shandralor-streamlit-password-generator-app-dzbr8y.streamlit.app\/\" data-type=\"URL\" data-id=\"https:\/\/shandralor-streamlit-password-generator-app-dzbr8y.streamlit.app\/\" target=\"_blank\" rel=\"noreferrer noopener\">You can find a live demo of the app here.<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>5\/5 &#8211; (1 vote) Project Description Both in my day job and personal life, I notice every day how important online security has become. Almost every part of our everyday lives are connected somehow to the Internet. And everyone of those connections requires (or should need) a password at the least. The problem with that [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[857],"tags":[73,468,528],"class_list":["post-131669","post","type-post","status-publish","format-standard","hentry","category-python-tut","tag-programming","tag-python","tag-tutorial"],"_links":{"self":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/131669","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/comments?post=131669"}],"version-history":[{"count":0,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/131669\/revisions"}],"wp:attachment":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media?parent=131669"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/categories?post=131669"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/tags?post=131669"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}