Web Authentication and Authorization
Introduction¶
A good resource is here.
Basic Authentication¶
Info
- Involves sending a username and password with each request, but can be less secure without encryption.
- Suitable for simple applications where security and encryption aren’t the primary concern or when used over secured connections.
sequenceDiagram
participant Client
participant Server
Client->>Server: 1. Requests Resource
Server->>Client: 2. Requests username/password
Client->>Server: 3. Sends username/password
Server->>Client: 4. Returns Resource
Token Authentication¶
Info
- Uses generated tokens, like JSON Web Tokens (JWT), exchanged between client and server, offering enhanced security without sending login credentials with each request.
- Ideal for more secure and scalable systems, especially when avoiding sending login credentials with each request is a priority.
sequenceDiagram
participant Client
participant Server
Client->>Server: 1. User logs in
Server->>Client: 2. Sends encrypted token
Client->>Server: 3. Sends Auth request with token
Server->>Client: 4. Returns Resource
Types of Tokens¶
- Access Tokens
- Refresh Tokens
Access tokens are used to grant access to a protected resource. When a client first authenticates it is given both types of tokens, but the access token is set to expire after a short period.
Refresh tokens are used to obtain a new access token when the current access token becomes invalid or expires, or to obtain additional access tokens with an identical or narrower scope. It does not need the credential information again. The refresh token is also valid for some duration, but it is much more than an access token.
JWT - JSON Web Token¶
Info
A JSON Web Token (JWT) is a standard that defines a safe, compact, and self-contained way of transmitting information between a client and a server in the form of a JSON object. A JWT can either be signed (JWS) or encrypted (JWE) or both. If a JWT is neither signed nor encrypted, then it is called an insecure JWT.
JWT structure¶
A JSON Web Token is basically three base64-encoded strings separated by a . (dot)
HEADER.PAYLOAD.SIGNATURE
1. Header¶
This is the first part of JWT. It is also known as the JOSE header (JSON Object Signing and Encryption). This header describes what algorithm is used to sign or encrypt the data contained in the JWT.
The header defines two attributes:
alg
: the algorithm used to sign or encrypt the JWT.typ
: the content that is being signed or encrypted.
The header JSON looks like as shown below.
Now when we encode it to base64encode, we get the first part of our JSON web tokeneyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9
.
2. Payload¶
This is the second part of JWT. It contains the main information that the server uses to identify the user and permissions. The payload consists of claims. Claims are statements about an entity (typically the user) and additional data.
There are three types of claims.
2.1. Registered Claim Names
These are reserved names that provide a starting point for a set of useful, interoperable claims.
iss
: identifies the principal that issued the JWT.sub
: identifies the principal that is the subject of the JWT.aud
: identifies the recipients that the JWT is intended for.exp
: identifies the expiration time at or after which the JWT MUST NOT be accepted for processing.nbf
: identifies the time before which the JWT MUST NOT be accepted for processing.iat
: identifies the time at which the JWT was issued.jti
: The JWT ID is a unique identifier for the JWT.
2.2. Public Claim Names
Public claim names are JSON Web Token Claims that can be defined at will by those using JWTs. However, in order to prevent collisions, any new claim name SHOULD either be defined in the IANA Registry, JSON Web Token Claims Registry, or be defined as a URI that contains a collision resistant namespace.
2.3. Private Claim Names
A producer and consumer of a JWT may agree to any Private claim name that is not a Reserved claim name or a Public claim name. Unlike Public claim names, these Private claim names are subject to collision and should be used with caution.
3. Signature¶
The third and final part of JWT is the signature. It is created by combining the header and payload parts of JWT and then hashing them using a secret key.
Full example from jwt.io
OAuth Authentication¶
Info
- Enables third-party limited access to user resources without revealing credentials by issuing access tokens after user authentication.
- Ideal for scenarios requiring controlled access to user resources by third-party applications or services.
sequenceDiagram
participant Client as Application (Client)
participant User as Resource Owner (User)
participant AuthServer as Authorization Server
participant ResourceServer as Resource Server
Client->>User: 1. Authorization request
User->>Client: 2. Authorization grant
Client->>AuthServer: 3. Authorization grant
AuthServer->>Client: 4. Access token
Client->>ResourceServer: 5. Access token
ResourceServer->>Client: 6. Returns Resource
Here is a more detailed explanation of the steps in the diagram:
- The application requests authorization to access service resources from the user.
- If the user authorized the request, the application receives an authorization grant (a credential representing the resource owner’s authorization to access its protected resources
- The application requests an access token from the authorization server (API) by presenting authentication of its own identity, and the authorization grant.
- If the application identity is authenticated and the authorization grant is valid, the authorization server (API) issues an access token to the application. Authorization is complete.
- The application requests the resource from the resource server (API) and presents the access token for authentication.
- If the access token is valid, the resource server (API) serves the resource to the application.
Grant Types¶
Info
Grant type refers to the way an application gets an access token. Each grant type is optimized for a particular use, whether that’s a web app, a native app, a device without the ability to launch a web browser, or server-to-server applications.
Some good resource regarding different grant types are here and here.
1. Authorization Code Grant Type¶
Note
The Authorization Code grant type is the most commonly used OAuth 2.0 grant type. It is used by both web apps and native apps to get an access token from the authorization server once the user has authorized. The Authorization Code flow is most suitable for websites and mobile apps that have a backend.
This type has the extra step of exchanging the authorization code for the access token. The exchange of authorization code for the access token takes place in the back channel. Due to this feature, it provides an additional layer of security.
Here is the high-level overview of the Authorization Code flow:
- The user clicks on a link or button on a web page that requests access to a resource.
- The user is redirected to the Authorization Server, where they authenticate themselves and grant permission to the requesting application.
- The Authorization Server generates an authorization code and redirects the user back to the requesting application with the authorization code.
- The requesting application exchanges the authorization code for an access token that can be used to access the protected resource.
sequenceDiagram participant User participant Client as Client (App) participant AuthServer as Authorization Server participant ResourceServer as Resource Server User->>Client: 1. User click "Login with OAuth2" Client ->> AuthServer: 2. Redirect to /authorize Note over Client,AuthServer: GET /authorize?<br/>response_type=code<br/>&client_id=12345<br/>&redirect_uri=https://client.dummy.com/callback<br/>&scope=images_read<br/>&state=abcde AuthServer->>User: 3. Prompt for login and consent User->>AuthServer: 4. Enter credentials and consent AuthServer->>Client: 5. Redirect to client callback URL with code Note over AuthServer,Client: GET /callback?<br/>code=hhdf6hsbhjG66hgtgfGGHJGCHJ<br/>&state=abcde Client->>AuthServer: 6. Exchange code (+ client_secret) for token Note over Client,AuthServer: POST /token<br/>grant_type=authorization_code<br/>code=hhdf6hsbhjG66hgtgfGGHJGCHJ<br/>client_id=12345<br/>client_secret=gh5Gdkj743HFG45udbfGfs AuthServer->>Client: 7. Return Access Token (+ Optional Refresh Token) Note over AuthServer,Client: HTTP 200 OK<br/>{<br/>"access_token": "YT3774ghsghdj6t4GJT5hd",<br/>"token_type": "bearer",<br/>"expires_in": 3600,<br/>"refresh_token": "YT768475hjsdbhdgby6434hdh",<br/>"scope": "images_read"<br/>} Client->>ResourceServer: 8. Request with Access Token ResourceServer->>Client: 9. Protected Resource
Step 1: Get the user's permission
The user clicks on a link or button on a web page that requests access to a resource. The requesting application sends a request to the Authorization Server with the following parameters:
response_type=code
: indicating the Authorization Code flow.client_id=12345
: the Client's unique identifier.redirect_uri
: The URI where the authorization server redirect to once it has finished interacting with the resource owner.scope=images_read
: The level of access being requested.state=abcde
: The application generates a random string and includes it in the request. It should then check that the same value is returned after the user authorizes the app. This is used to prevent CSRF attacks.
Step 2: Redirect to the Authorization Server
The user is redirected to the Authorization Server, where they authenticate themselves and grant permission to the requesting application. The Authorization Server could ask the user to log in or prompt them to authorize the access request.
Step 3: Redirect back to the app
If the user grants permission, the Authorization Server generates an authorization code and redirects the user back to the requesting application with the authorization code. The response includes:
code=hhdf6hsbhjG66hgtgfGGHJGCHJ
(the authorization code)state=abcde
(the same state value sent in step 1, for verification)
Step 4: Exchange code for token
The requesting application exchanges the authorization code for an access token that can be used to access the protected resource. The requesting application sends a POST request to the Authorization Server with the following parameters:
grant_type
: The value of this parameter should be set toauthorization_code
to indicate that the authorization code will be exchanged for an access token.client_id
: The ID of the client that is making the request.client_secret
: The client secret that is used to authenticate the client.code
: The authorization code that was received in the previous step.redirect_uri
: The URL where the Authorization Server redirected the user after they granted permission.
The Authorization Server validates the request and responds with an access token and a refresh token (if enabled). The requesting application can use the access token to access the protected resource.
2. Implicit Grant Type¶
Note
The Implicit grant type is designed for single-page JavaScript apps that do not have a backend and have no way to store client secrets. Storing the client secret in the JavaScript code is not as safe, because anyone can access it. Therefore, we use the Implicit flow for these apps.
In Implicit flow, the authorization server directly returns the access token instead of returning the code. This flow type should be used only if there is no alternative option because it is not safe. The exchange of token happens at the front end and an attacker can access the token.
sequenceDiagram
participant Client
participant User
participant AuthServer as Authorization Server
participant ResourceServer as Resource Server
Client->>User: 1. Authorization Request
User->>AuthServer: 2. Authorize Client
AuthServer->>User: 3. Access Token
User->>Client: 4. Access Token
Client->>ResourceServer: 5. Request with Access Token
ResourceServer->>Client: 6. Protected Resource
3. Client Credentials Grant Type¶
Note
This grant type is used for machine to machine authorization. There is no user involved in this flow. Suppose we have an application that follows the microservices architecture. The application is divided into small parts and each part is deployed on a separate server.
If one internal server needs to access some data from the other server, then they can use the client credentials grant type.
sequenceDiagram
participant Client
participant AuthServer as Authorization Server
participant ResourceServer as Resource Server
Client->>AuthServer: 1. Client Credentials
AuthServer->>Client: 2. Access Token
Client->>ResourceServer: 3. Request with Access Token
ResourceServer->>Client: 4. Protected Resource
4. Resource Owner Password Credentials Grant Type¶
Note
The Resource Owner password credentials grant type is used in cases where the resource owner trusts the client and is ready to share its credentials with the client. The authorization server should take special care when enabling this grant type and only allow it when other flows are not viable.
This flow was introduced to migrate existing clients using direct authentication schemes such as HTTP Basic or Digest authentication to OAuth by converting the stored credentials to an access token. Today, there is no case in which this flow should be used, as it is very insecure.
sequenceDiagram
participant Client
participant AuthServer as Authorization Server
participant ResourceServer as Resource Server
Client->>AuthServer: 1. Resource Owner Credentials + Client Credentials
AuthServer->>Client: 2. Access Token (+ Optional Refresh Token)
Client->>ResourceServer: 3. Request with Access Token
ResourceServer->>Client: 4. Protected Resource
API Key Authentication¶
Info
- Assigns unique keys to users or applications, sent in headers or parameters; while simple, it might lack the security features of token-based or OAuth methods.
- Convenient for straightforward access control in less sensitive environments or for granting access to certain functionalities without the need for user-specific permissions.