Loading...
Loading...
Backend interview guide
Authentication, authorization, JWT, password hashing and securing endpoints. Every answer is short enough to say aloud, and every question links to the lesson that teaches it.
60 questionsLast updated
The request is valid field by field; it conflicts with existing data. That is 409 Conflict in our contract, with the already-exists type, the same as a duplicate SKU.
Lesson: Handling duplicate emailssave may delay the INSERT until commit, which happens after the method returns, so the try-catch never sees the constraint error and the client gets a 500. saveAndFlush runs the SQL immediately inside the try.
Lesson: Handling duplicate emailsAs a slow, salted one-way hash, such as BCrypt with a measured cost or Argon2, never as text or with reversible encryption. In Spring I use the delegating PasswordEncoder so each hash carries its algorithm id, and I check with matches.
Lesson: Practice: users and password storageThat the password goes through the shared PasswordEncoder before saving, that no request or entity is logged or returned with a password or hash, that the request record has validation and no role field, and that duplicates are guarded by a unique constraint.
Lesson: Practice: users and password storageBecause it allows an offline guessing attack with no rate limit and no log on our side. Weak passwords would be found quickly; the hash is only useful to the sign-in check, so it stays there.
Lesson: Practice: users and password storageSign-in gives the same 401 for an unknown e-mail and a wrong password, so it reveals nothing. Sign-up returns 409 for an existing e-mail, which does reveal an account: a trade-off we accept for a clear message, with rate limits as protection.
Lesson: Practice: users and password storageThe client sends Authorization: Basic followed by the Base64 of username:password on every request. The server decodes it, checks the password against the stored hash and either handles the request or answers 401 with WWW-Authenticate: Basic. Nothing is stored between requests.
httpBasic(Customizer.withDefaults())?It adds the BasicAuthenticationFilter and a Basic entry point. The filter decodes the header and passes the credentials to the AuthenticationManager, which uses the UserDetailsService and PasswordEncoder. On success the user is put in the SecurityContext for that request; on failure the entry point sends 401 with WWW-Authenticate.
Every request is another chance for the password to leak into a log, a proxy, a crash report or a screenshot. It also makes the server run a slow password hash on every call and lets attackers guess passwords on any endpoint. With a login step, later requests carry a session id or a short-lived token instead.
Lesson: HTTP Basic authenticationThe API answers with WWW-Authenticate: Basic, and browsers react to that header with their own dialog. A browser app should sign in once and then use a session cookie or a bearer token; a bearer 401 does not trigger the dialog.
HttpOnly hides the cookie from JavaScript, so XSS cannot read it. Secure makes the browser send it only over HTTPS. SameSite=Lax or Strict stops the browser from attaching it to most requests that other sites start, which is a defence against CSRF.
POST /logout with a valid CSRF token invalidates the HttpSession, clears the SecurityContext and redirects to /login?logout. The cookie stays in the browser unless you add deleteCookies("JSESSIONID"), but it no longer points to a session.
Each server keeps its own sessions in memory, so a request routed to another server does not find the session and the user looks logged out. You need sticky sessions, a shared store such as Spring Session with Redis or JDBC, or stateless tokens, and each choice has a cost.
Lesson: Form login and session cookiesCross-site request forgery is when another website makes a signed-in user's browser send a state-changing request to your site. It works because the browser attaches your cookies automatically, so the server cannot tell the forged request from a real one without an extra check.
Lesson: CSRF and when it mattersCSRF protection is on by default and the request has no token. For a cookie-based app you must send the token; for a stateless API that uses the Authorization header, CSRF protection should be disabled in the security configuration.
Lesson: CSRF and when it mattersWhen the browser never sends credentials automatically: the client adds an Authorization header in its own code and there are no auth cookies. That is the usual stateless REST API with bearer tokens. If credentials are in cookies, or a browser remembers Basic credentials, keep it on.
With csrf.spa() Spring puts the token in a readable XSRF-TOKEN cookie; the app reads it with JavaScript and sends it back in the X-XSRF-TOKEN header. Another site can make the browser send the cookies but cannot read them, so it cannot build the header.
With sessions, the server stores the signed-in user and the client sends a session id, usually in a cookie. With tokens, the client sends a signed token holding the user and an expiry, and the server only checks the signature. Sessions are easy to revoke; tokens are easy to scale.
Lesson: Why stateless APIs prefer tokensA mobile app has no browser cookie handling to lean on, and the API often runs on several servers. A token kept in the phone's secure storage and sent in the Authorization header works with any server that has the key and avoids CSRF.
Lesson: Why stateless APIs prefer tokensNo. For a server-rendered website on one or a few servers they are simple and safe: logout works at once and the cookie can be HttpOnly, Secure and SameSite. You just keep CSRF protection on and plan for scaling with sticky sessions or a shared store.
Lesson: Why stateless APIs prefer tokensFor an API used by mobile apps or single-page apps and run on several servers, short-lived tokens in the Authorization header: any server can check them and CSRF is not a risk. I would pair them with refresh tokens that the server can revoke, because a stateless access token cannot be deleted.
Lesson: Practice: HTTP Basic, sessions and CSRFThe app would have to store the customer's real password and send it with every request, there is no logout or expiry, and every request runs a slow hash check. A token from a one-time login is safer.
Lesson: Practice: HTTP Basic, sessions and CSRFNo. The browser's same-origin policy stops the other site from reading it. The attacker only wants the side effect, such as a changed email or a placed order, which is why state-changing requests need the token.
Lesson: Practice: HTTP Basic, sessions and CSRFIt is expected for stateless tokens: nothing on the server can delete them. The design answer is a short lifetime, revoking the refresh token on logout, and a deny-list only if instant cut-off is required.
Lesson: Practice: HTTP Basic, sessions and CSRFA JSON Web Token is a compact, signed text that carries claims about a user. It has three Base64URL parts separated by dots: a header with the algorithm, a payload with the claims, and a signature over the first two parts.
Lesson: JWT structure: header, payload, signatureThe issuer (iss), the user id as sub, iat and a short exp, and the roles the API needs for access rules, perhaps a customer id. Nothing that changes often or is private: names, e-mails and addresses are loaded from the database when needed.
Some libraries trusted the alg in the token header, so an attacker sent alg: none with an empty signature and any claims they liked. The fix is that the server fixes the expected algorithm and key and rejects anything else. In Spring Security that is macAlgorithm(MacAlgorithm.HS256) on the NimbusJwtDecoder.
Yes. exp is inside the signed payload, so the server checks the signature and then compares exp with its own clock. That is the main attraction of JWTs: the check is local. The downside is that a valid token cannot easily be cancelled early, which later lessons deal with.
The provider behind it already checks the enabled flag, uses matches correctly, erases the password after use and runs a dummy hash for unknown users so timing does not leak which e-mails exist. Reusing it means less security code of my own to get wrong.
If unknown e-mails and wrong passwords answered differently, an attacker could first find which e-mails have accounts, then try passwords only on those. One generic 401 and similar timing give them nothing to work with.
Lesson: Login endpoint that returns a tokenAnyone could sign tokens with any roles, including ADMIN, and the API would accept them. So the secret lives only in an environment variable on the server, never in Git, and a leak means rotating the key at once, which logs everyone out.
Lesson: Login endpoint that returns a tokenA hand-written OncePerRequestFilter has to handle missing and duplicate headers, error responses with the right WWW-Authenticate header, clearing the context and the algorithm check. The built-in filter already does all of that and is tested by the Spring team, so my code is just the decoder and a converter.
From the roles claim that I wrote at login. A JwtGrantedAuthoritiesConverter reads that claim and adds ROLE_, so hasRole("ADMIN") works. By default Spring would read scope and add SCOPE_ instead.
I give the security chain an AuthenticationEntryPoint and an AccessDeniedHandler. They let Spring's bearer versions set the status and WWW-Authenticate header and then write the same ProblemDetail JSON that the global handler uses.
Short, minutes rather than days; ShopLite uses 15 minutes. A JWT cannot be cancelled before exp, so the lifetime is how long a stolen token works. The refresh token keeps users signed in without long access tokens.
Keys get reused across test servers and apps, so a valid signature can still come from a token made for something else. JwtIssuerValidator makes sure iss is our own API. Also, setJwtValidator replaces the defaults, so I always put the timestamp check in the same list.
At least 256 bits, which is 32 bytes. I make it with openssl rand -base64 32 or SecureRandom, never a word or a password, because a short secret can be brute-forced offline from any token.
setJwtValidator(new JwtIssuerValidator(...)) alone?Expired tokens are accepted, because the call replaces the default validators that checked exp. The fix is a DelegatingOAuth2TokenValidator with the timestamp validator and the issuer validator together.
Every refresh token can be used once: the refresh endpoint revokes it and returns a new one. If a revoked token ever comes back, someone has a copy, so I revoke the whole family of tokens from that login and both parties must sign in again.
Lesson: Refresh tokens and logout (the trade-offs)No, it is a random 32-byte string. It never needs to be read by anyone except my server, which looks it up anyway, so a JWT would only add a payload to leak and a signature to manage.
Lesson: Refresh tokens and logout (the trade-offs)It depends on the client. For a mobile app or single-page app calling an API, short JWTs plus rotated refresh tokens. For a server-rendered site on one domain, sessions are simpler and give instant logout, with CSRF protection for the cookie.
Lesson: Refresh tokens and logout (the trade-offs)Two requests with the same refresh token at the same time could both succeed and create two families. I lock the row with SELECT ... FOR UPDATE, so the second request waits and then sees a revoked token, which is treated as reuse.
Any script on the page can read it, so a single XSS bug, even in a third-party widget, lets an attacker copy the tokens and use them from their own machine. For a refresh token that can mean days of access.
Lesson: Where clients should store tokensNo. It stops the attacker from stealing the token, but their script can still make requests from the victim's open page while it runs. The real fix for XSS is escaping output and a Content Security Policy; storage choices limit the damage.
Lesson: Where clients should store tokensURLs are written to access logs, proxies and browser history and sent in Referer headers, so each becomes a copy of the token. Spring Security even ignores access_token in the query by default; the token belongs in the Authorization header over HTTPS.
Sessions keep state on the server, give instant logout and suit websites on one domain, but need CSRF protection and shared session storage across servers. JWTs are checked with a key alone, so they scale and suit mobile apps and APIs, but cannot be revoked before exp, so they must be short-lived.
Each refresh token works once and is replaced at every refresh. If an old one is used again, a copy exists, so I revoke the whole family and both the attacker and the user must log in again. Without rotation a stolen refresh token would work for its whole lifetime.
Lesson: Practice: JWT authenticationAn attacker sends a token with "alg":"none" and no signature, hoping the server trusts the header. My decoder only accepts HS256, so such a token is rejected with "Unsupported algorithm of none" before any claim is read.
The WWW-Authenticate header and the log: "Invalid signature" means encoder and decoder keys differ; "iss claim is not valid" means different issuer settings; "Jwt expired" with fresh tokens means clocks are out of sync. I would also confirm the client sends Authorization: Bearer and not a query parameter.
I print the authorities of the current Authentication. If they show ROLE_ROLE_ADMIN, the prefix is added twice, once in the data or token and once in the converter. I store bare role names and add ROLE_ in exactly one place.
It says one role includes another, so ADMIN > CUSTOMER lets admins pass every hasRole("CUSTOMER") rule. I avoid it when a lower role's rules depend on data the higher role does not have. In ShopLite an admin has no customer profile, so /me/orders must stay customer-only.
No. Editing the payload breaks the HS256 signature, so the decoder rejects the token with 401 before any rule runs. The roles are trusted only because the server signed them.
Lesson: Roles vs authoritiesIn order, top to bottom, in the AuthorizationFilter. The first requestMatchers rule that matches the method and path decides, and later rules are not checked. So I put specific rules first and anyRequest() last.
The last rule is anyRequest().denyAll(), so any path that no rule names is refused. If someone adds an endpoint and forgets the security table, it is closed instead of open. In ShopLite a guest then gets 401 and even an admin gets 403 until a rule is added on purpose.
URL rules cover whole groups of endpoints in one place, including endpoints added later, and refuse requests before any application code runs. Checks spread over controllers are easy to forget once. I still add method security and owner checks for what URLs cannot express.
Lesson: URL rules with requestMatchersNo. The rule sees /api/v1/orders/14 and the caller's role, but not who owns order 14. Ownership needs data, so it is checked in the service, which answers 404 for other people's orders.
@EnableMethodSecurity makes Spring wrap the bean in a proxy. The proxy evaluates the SpEL rule with the current Authentication and the method arguments, and only then calls the real method; otherwise it throws AuthorizationDeniedException. That is also why calls on this inside the class are not checked.
Only for reads without side effects, where the rule depends on the returned object and loading it first is acceptable. For ownership I prefer filtering in the query and answering 404, because @PostAuthorize runs the method first and its 403 reveals that the data exists.
I write a small Spring test with @EnableMethodSecurity, the one service and mocks for its dependencies. With @WithMockUser(roles = "CUSTOMER") I assert AuthorizationDeniedException and verifyNoInteractions on the repository, and with an admin I assert that the method body ran.
IDOR means the server returns an object for an id from the request without checking the caller may see it. In ShopLite every order endpoint passes the caller from the token into the service, which loads orders by id and customer id together, so other customers' orders are simply not found. Admins use the plain query.
Lesson: Owner checks: a customer sees only their own ordersEach lesson has quizzes, practice and more interview questions on the same topic.
Open the first lesson