|
| 1 | +[](https://stand-with-ukraine.pp.ua) |
| 2 | + |
| 3 | +# Rust Rocket MongoDB token-auth REST API boilerplate |
| 4 | + |
| 5 | + |
| 6 | +In this repository, you can find backend Rust rocket mongodb rest-api |
| 7 | +boilerplate with token authorization. |
| 8 | + |
| 9 | +```rust |
| 10 | +#[get("/public/hello")] |
| 11 | +pub async fn hello_world() -> Json<&'static str> { |
| 12 | + Json("Hello world") |
| 13 | +} |
| 14 | +``` |
| 15 | + |
| 16 | +Visiting `localhost:8000/api/v1/public/hello`, for example, will trigger the `hello` |
| 17 | +route resulting in the string `Hello world` being sent to the |
| 18 | +browser. In this example there is no authorization. |
| 19 | + |
| 20 | +## How to start |
| 21 | +1. First you need to download this repository to your computer |
| 22 | + |
| 23 | +* Write this in your terminal: |
| 24 | + |
| 25 | +```sh |
| 26 | +git clone https://github.com/martyr00/Rust-rocket-mongoDB-token-auth-REST-API-boilerplate.git |
| 27 | +``` |
| 28 | +* After open the project in your IDE |
| 29 | + |
| 30 | +2. You need to make your private.rs file as in the private.sample.rs: |
| 31 | + |
| 32 | +```rust |
| 33 | +pub const JWT_SECRET: &[u8] = b"<YOUR_JWT_SECRET_KEY>"; |
| 34 | +pub const REFRESH_JWT_SECRET: &'static str = b"<YOUR_REFRESH_JWT_SECRET_KEY>"; |
| 35 | +pub(crate) const URL_DB: &str = "mongodb+srv://<YOUR_LOGIN>:<YOUR_PASSWORD>@cluster0.d5yn0.mongodb.net/<YOUR_DB_NAME>"; |
| 36 | +``` |
| 37 | + |
| 38 | + * `JWT_SECRET` and `REFRESH_JWT_SECRET` you need to come up with your own secret word to encrypt the tokens |
| 39 | + * For `URL_DB` you need registration your mongoDB acc here https://cloud.mongodb.com/ |
| 40 | + |
| 41 | +3. To run write this in your terminal: |
| 42 | + |
| 43 | +```sh |
| 44 | +cargo check && cargo run |
| 45 | +``` |
| 46 | + |
| 47 | +## Routes |
| 48 | + |
| 49 | +* /api/v1/registration (POST) |
| 50 | +* /api/v1/login (POST) |
| 51 | +* /api/v1/refresh (POST) |
| 52 | +* /api/v1/public/hello (GET) |
| 53 | +* /api/v1/hello (GET) |
| 54 | +* /api/v1/public/user (DELETE, PATCH) |
| 55 | + |
| 56 | +## Registration acc |
| 57 | + |
| 58 | +### Registration request: |
| 59 | +* `login` (must be unique && len login must be from 3 to 200 letter) |
| 60 | +* `password` (len password must be from 8 to 200 letter and password is hashed before being saved to the database.) |
| 61 | +* `mail` (must be unique and mail) |
| 62 | +* `first_name` (len must be from 2 to 150 letter and this field is optional) |
| 63 | +* `last_name` (len must be from 2 to 200 letter and this field is optional) |
| 64 | + |
| 65 | +```rust |
| 66 | +pub struct RegistrationRequest { |
| 67 | + pub login: String, |
| 68 | + pub password: String, |
| 69 | + |
| 70 | + pub mail: String, |
| 71 | + |
| 72 | + pub first_name: String, |
| 73 | + pub last_name: String, |
| 74 | +} |
| 75 | +``` |
| 76 | +#### Example registration request: |
| 77 | + |
| 78 | +```json |
| 79 | +{ |
| 80 | + "login": "test", |
| 81 | + "password": "12345678", |
| 82 | + |
| 83 | + "first_name": "Test", |
| 84 | + "last_name": "" |
| 85 | +} |
| 86 | +``` |
| 87 | + |
| 88 | +### Registration response |
| 89 | + |
| 90 | +In response, the server will send 2 JWT tokens. |
| 91 | +The `token` is valid for 1 hour. `Refresh token` is valid for 7 days. |
| 92 | +`token` is needed to verify user authorization. |
| 93 | +With each private request, the `token` will be sent fronted to |
| 94 | +the headers in the authorization field. |
| 95 | + |
| 96 | +More about jwt authentication https://blog.logrocket.com/jwt-authentication-in-rust/ |
| 97 | + |
| 98 | +#### If everything is correct: |
| 99 | +```rust |
| 100 | +pub struct Token { |
| 101 | + pub token: String, |
| 102 | + pub refresh_token: String, |
| 103 | +} |
| 104 | +``` |
| 105 | +#### Example: |
| 106 | + |
| 107 | +```json |
| 108 | +{ |
| 109 | + "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNjJiNGRhOTk4ZjgyMzc2YTk1MzM1MWIxIiwiZXhwIjoxNjU2MDIzMjA5fQ.aJFDZVyMBuNYh5EAArYYfzYCTnHHCQ7IHuZpKNCXHs0", |
| 110 | + "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNjJiNGRhOTk4ZjgyMzc2YTk1MzM1MWIxIiwiZXhwIjoxNjU4NjExNjA5fQ.2_DjxtQxtsLsprvhBfYU8rKAoDfWMdshoPKDUqq6QZQ" |
| 111 | +} |
| 112 | +``` |
| 113 | +#### Possible error: |
| 114 | + |
| 115 | +* `bad login` -> Status 400 and string "Bad login" in json |
| 116 | +* `already registered login` -> Status 400 and string "Already registered by login" in json |
| 117 | +* `bad password` -> Status 400 and string "Bad password" in json |
| 118 | +* `already registered password` -> Status 400 and string "Already registered by password" in json |
| 119 | +* `bad mail` -> Status 400 and string "Bad mail" in json |
| 120 | +* `already registered mail` -> Status 400 and string "Already registered by mail" in json |
| 121 | + |
| 122 | +#### Example error: |
| 123 | + |
| 124 | +Status 400 Bad Request |
| 125 | +```json |
| 126 | +{ |
| 127 | + "cause": "Already registered by login" |
| 128 | +} |
| 129 | +``` |
| 130 | + |
| 131 | +## Login acc |
| 132 | + |
| 133 | +### Login request: |
| 134 | + |
| 135 | +* `login`(The server checks 2 logins from the database and the request) |
| 136 | +* `password`(The server checks the encrypted password in the |
| 137 | + database with the password from the request) |
| 138 | + |
| 139 | +```rust |
| 140 | +pub struct LoginRequest { |
| 141 | + pub login: String, |
| 142 | + pub password: String, |
| 143 | +} |
| 144 | +``` |
| 145 | + |
| 146 | +#### Example: |
| 147 | +```json |
| 148 | +{ |
| 149 | + "login": "test", |
| 150 | + "password": "12345678" |
| 151 | +} |
| 152 | +``` |
| 153 | + |
| 154 | +### Login response: |
| 155 | + |
| 156 | +#### If everything is correct: |
| 157 | +```rust |
| 158 | +pub struct Token { |
| 159 | + pub token: String, |
| 160 | + pub refresh_token: String, |
| 161 | +} |
| 162 | +``` |
| 163 | + |
| 164 | +#### Example: |
| 165 | + |
| 166 | +```json |
| 167 | +{ |
| 168 | + "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNjJhM2I3Zjg4MTE1OWVkYWJmNTcwZjYwIiwiZXhwIjoxNjU2MDI0MDM1fQ.5Nu0lbN5X656JhuY8PrK1IJhWFVjHxKbh8CssKqHQqk", |
| 169 | + "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNjJhM2I3Zjg4MTE1OWVkYWJmNTcwZjYwIiwiZXhwIjoxNjU4NjEyNDM1fQ.5OUiED1no-uizfYmq1xk6Z6XpX9TsbezDx8QxPSbyV0" |
| 170 | +} |
| 171 | +``` |
| 172 | + |
| 173 | +#### Possible error: |
| 174 | +* `Bad request`(In any case) |
| 175 | + |
| 176 | +#### Example: |
| 177 | + |
| 178 | +Status 400 |
| 179 | +```json |
| 180 | +{ |
| 181 | + "cause": "Wrong request" |
| 182 | +} |
| 183 | +``` |
| 184 | + |
| 185 | +## Refresh token |
| 186 | +In this route, the frontend asks the server to |
| 187 | +refresh the `token` with a `refresh token` in json |
| 188 | + |
| 189 | +### Refresh token request |
| 190 | +* `refresh token`(specific user) |
| 191 | + |
| 192 | +```rust |
| 193 | +pub struct RefreshToken { |
| 194 | + pub(crate) refresh_token: String, |
| 195 | +} |
| 196 | + |
| 197 | +``` |
| 198 | + |
| 199 | +#### Example refresh token request: |
| 200 | +```json |
| 201 | +{ |
| 202 | + "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNjJhM2I3Zjg4MTE1OWVkYWJmNTcwZjYwIiwiZXhwIjoxNjU3NDg5NDcyfQ.BcTanbs5lyT-Yv2ekf5-xl_NzEqpKsh5S59AEuZrmVQ" |
| 203 | +} |
| 204 | +``` |
| 205 | + |
| 206 | +### Refresh token response |
| 207 | + |
| 208 | +#### If everything is correct: |
| 209 | +```rust |
| 210 | +pub struct Token { |
| 211 | + pub token: String, |
| 212 | + pub refresh_token: String, |
| 213 | +} |
| 214 | +``` |
| 215 | + |
| 216 | +#### Example: |
| 217 | + |
| 218 | +```json |
| 219 | +{ |
| 220 | + "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNjJhM2I3Zjg4MTE1OWVkYWJmNTcwZjYwIiwiZXhwIjoxNjU2MDI0MDM1fQ.5Nu0lbN5X656JhuY8PrK1IJhWFVjHxKbh8CssKqHQqk", |
| 221 | + "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNjJhM2I3Zjg4MTE1OWVkYWJmNTcwZjYwIiwiZXhwIjoxNjU4NjEyNDM1fQ.5OUiED1no-uizfYmq1xk6Z6XpX9TsbezDx8QxPSbyV0" |
| 222 | +} |
| 223 | +``` |
| 224 | + |
| 225 | +#### Possible error: |
| 226 | +* `Unauthorized` |
| 227 | + |
| 228 | +#### Example: |
| 229 | + |
| 230 | +Status 400 |
| 231 | +```json |
| 232 | +{ |
| 233 | + "cause": "Unauthorized" |
| 234 | +} |
| 235 | +``` |
| 236 | + |
| 237 | +## Public hello |
| 238 | + |
| 239 | +This is the only route without authorization. Therefore there is no request in this route. |
| 240 | + |
| 241 | +### Rust code: |
| 242 | +```rust |
| 243 | +#[get("/public/hello")] |
| 244 | +pub async fn hello_world() -> Json<&'static str> { |
| 245 | + Json("Hello world") |
| 246 | +} |
| 247 | +``` |
| 248 | +### Response in json: |
| 249 | +``` |
| 250 | +{ |
| 251 | + "Hello world" |
| 252 | +} |
| 253 | +``` |
| 254 | + |
| 255 | +## Private hello |
| 256 | +In this route, the server checks in the headers |
| 257 | +token if the token is valid then the server executes the program. |
| 258 | + |
| 259 | +### Private hello request: |
| 260 | +#### From headers: |
| 261 | + |
| 262 | +`authorization` `Bearer` (TOKEN) |
| 263 | + |
| 264 | +#### Example: |
| 265 | + |
| 266 | +`authorization` `Bearer eyJ0eXAiOiJKV1QiLCJhbGci....` |
| 267 | + |
| 268 | +### Private hello response |
| 269 | + |
| 270 | +the response will be a greeting with the user. |
| 271 | +If the database contains his first name and surname, |
| 272 | +then the program will greet you by the first name and |
| 273 | +surname; if not, the program will greet you by login |
| 274 | + |
| 275 | +#### If everything is correct: |
| 276 | + |
| 277 | +```rust |
| 278 | +pub struct HelloNameResponse { |
| 279 | + pub(crate) greetings: String, |
| 280 | +} |
| 281 | +``` |
| 282 | +#### Example: |
| 283 | +```json |
| 284 | +{ |
| 285 | + "greetings": "Hello test" |
| 286 | +} |
| 287 | +``` |
| 288 | + |
| 289 | +#### Possible error: |
| 290 | +* `Unauthorized` |
| 291 | + |
| 292 | +#### Example: |
| 293 | +Status 401 |
| 294 | + |
| 295 | +```json |
| 296 | +{ |
| 297 | +"cause": "Unauthorized" |
| 298 | +} |
| 299 | +``` |
0 commit comments