What is JWT & What is it used for ?
What is JWT?
JWT (JSON Web Token) is an Internet standard between client and server for creating JSON-based access tokens that assert some number of claims. JWT provides authorization for users.
What is it used for ?
- Let me give you an example to explain this concept in basic terms.
Let’s assume we have a mobile application (client-side) which communicates with backend(server-side) via web services and this application has many users. After user login, we may need to figure who is calling our services out (because our application has user-based operations, records etc.) or we may need to decide whether the request coming from an user or coming from an admin.
At this point we need to create a token that includes user info (securely).
Let’s take a look the flow of JWT as shown below,
- Login Request: User logins with id/password, facebook account etc.
- Login Response: Then JWT creates a token which contains user id etc. securely and returns it to the the user.
- Service Request: User send request to a service at server-side by token(token at login response) at header.
- Service Response: Then server converts securely token to extract user id and find who is calling this service. It generates a token again for next call and refresh the expire date and returns it to the user.
That’s all.
Let’s deep down more.
JSON Web Token occurs from three parts.
- Header
- Payload
- Signature
Header => The header typically consists of two parts: the type of the token(which is JWT) and the signing algorithm being used, such as HMAC SHA256 or RSA.
{
“alg” : “HS256”, //HMAC-SHA256
“typ” : “JWT” //our type
}
Payload => The payload contains the claims. Claims are statements about an entity (typically, the user) and additional data. It is user id for the example i share above. (PS: You can have multiple claims).
{
“name” : “1546” //user id, i keep user id under name claim
}
Signature => The signature securely validates the token. It is calculated by encoding the header and payload, running through the cryptographic algorithm specified in the header (HS256 in our example) and adding them secret key as shown below (Secret is any string you will determine, it is up to you).
HMAC-SHA256(
base64urlEncoding(header) + ‘.’ +
base64urlEncoding(payload),
“THIS IS MY SECRET KEY DID YOU LIKE IT” //secret key
)
Let’s Do An Example (by C#)
I have created a Web API project to show how JWT is done :)
First of all i want to show the files in my project.
Manager.cs
public class Manager : IManager {private List<User> userList = new List<User>();public Manager() {//Some dummy datauserList.Add(new User() { Id = 1, Name = "Furkan", Password = "qwerty", UserName = "Lion", Surname = "Öztürk" });userList.Add(new User() { Id = 2, Name = "Ali", Password = "asdasd1234", UserName = "asdsa34", Surname = "Ali" });userList.Add(new User() { Id = 3, Name = "Veli", Password = "ads334", UserName = "df5gt23", Surname = "Veli" });}public string Authenticate(string userName, string password) {var user = userList.FirstOrDefault(x => x.UserName.Equals(userName) && x.Password.Equals(password));if (user == null)return null;var tokenHandler = new JwtSecurityTokenHandler();var key = Encoding.ASCII.GetBytes("THIS IS MY SECRET KEY DID YOU LIKE IT");var tokenDescriptor = new SecurityTokenDescriptor {Subject = new ClaimsIdentity(new Claim[] {new Claim(ClaimTypes.Name, user.Id.ToString())}),Expires = DateTime.UtcNow.AddMinutes(5), //Expire Date is 5 minutesSigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)};var token = tokenHandler.CreateToken(tokenDescriptor);var result = tokenHandler.WriteToken(token);return result;}
IManager.cs
public interface IManager {string Authenticate(string userName, string password);}
User.cs
public class User {public int Id { get; set; }public string Name { get; set; }public string Surname { get; set; }public string UserName { get; set; }public string Password { get; set; }}
LoginRequestModel.cs
public class LoginRequestModel {public string userName { get; set; }public string password { get; set; }}
Startup.cs
public class Startup {public Startup(IConfiguration configuration) {Configuration = configuration;}public IConfiguration Configuration { get; }public void ConfigureServices(IServiceCollection services) {services.AddCors();services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);var key = Encoding.ASCII.GetBytes("THIS IS MY SECRET KEY DID YOU LIKE IT");services.AddAuthentication(x => {x.DefaultAuthenticateScheme = wtBearerDefaults.AuthenticationScheme;x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(x => {x.RequireHttpsMetadata = false;x.SaveToken = true;x.TokenValidationParameters = new TokenValidationParameters {ValidateIssuerSigningKey = true,IssuerSigningKey = new SymmetricSecurityKey(key),ValidateIssuer = false,ValidateAudience = false};});services.AddSingleton<IManager, Manager>();}public void Configure(IApplicationBuilder app, IHostingEnvironment env) {if (env.IsDevelopment()) {app.UseDeveloperExceptionPage();}app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());app.UseAuthentication();app.UseMvc();}}
Controller.cs
[Authorize][Route("api/[controller]")][ApiController]public class ValuesController : ControllerBase {private readonly IManager manager;public ValuesController(IManager manager) {this.manager = manager;}[AllowAnonymous][HttpPost("login")]public ActionResult<string> Login(LoginRequestModel model) {var token = manager.Authenticate(model.userName, model.password);return Ok(token);}[HttpGet("do")]public ActionResult<string> GetSelam() {return "Heyyyyy!!";}}
I just want to mention about a few things. [Authorize] attribute in controller, provides to reach all services of controller by valid token. [AllowAnonymous] attribute is to violate this rule, i mean you can reach any service with AllowAnonymous attribute without token. This is generally necessary for first calls (login). Do not forget that expire period is 5 minutes in my example and you can change it.
Test!!!
First i am going to try to call …/do service without token to see whether it returns a response.
As you can see, there is no response and service returns with 401 Unauthorized status.
Let’s try this with the right way
First i am going to call …/login service to see whether it returns a token.
As you can see, it returns token and service returns with 200 OK status.
Second i am going to call …/do service with this token (response of login service as we see above) to see whether it returns a response.
Let’s add our token to header (“Bearer “ + token) as i shown below
Then call the …/do service
and that is it. Service returns response “Heyyyyy!!”
THAT’S ALL!!!!
PS: You can autofill your header by login response token with postman commands.
- By adding the following commands to Tests tab of Login service,
postman.setEnvironmentVariable(“jwt_token”, responseBody);
If your service return json (more than one property) rather than a single property(token).
- You can extraxt token like,
var jsonData = JSON.parse(responseBody);
postman.setEnvironmentVariable(“jwt_token”, responseBody);
Make sure you have add “jwt_token” as a variable and changed your Authorization header as Bearer {{jwt_token}}
I have tried to be crystal clear.
I hope this will be helpful, thanks! 😊