Skip to content

Authorization

The authorization system makes use of JSON Web Tokens. These tokens contain base64 encoded user profile information that can be decoded by client or server applications. The tokens are signed with a secret key available in the API that allows the API to ensure that the tokens are not altered after being created. Our token system bootstraps off of Google's, which reduced the implementation overhead. The user's profile data come from Google, then the API requests what Google Groups that user is a part of and packages that JSON data into a token.

To make a request to the API from an external server, a token must be first obtained and passed in each request as a cookie called authHeaders. If logging in using /auth/client, this cookie is set in the users browser automatically, and it will be removed when it expires. Subsequent requests to the same top-level domain from when the cookie was obtained (e.g.https://hakai.org will automatically include the cookie in the request.

Alternatively, if it's not possible to store and save a cookie, the value of the JWT auth token can be saved somewhere and included in requests to hakai-api under the "Authorization" request header like so:

"Authorization": "Bearer eyu172319asdf..."

Auth endpoints

These endpoints should be used to obtain JWT tokens in web applications.

type url function
GET /auth/client Redirect users to the correct Google Sign in page url. After signing in, it will redirect the JWT token to be used in subsequent requests back to the requesting site in the form of querystring parameters. This can be overridden be setting ?state=http://url.to.redirect.to as a querystring parameter in the original request.
GET /auth/code2jwt Used internally to issue a JWT token to the user that requested one form the /auth/client url.
GET /auth/validate_token get the access-token from the header and verify it's valid. Return user profile.
* /auth/logout Clears any auth cookies from the requestors browser.
GET /auth/login Alias for /auth/client
GET /login Alias for /auth/client
* /logout Alias for /auth/logout

Authorization flow

    sequenceDiagram
    actor User
    participant Client
    participant API
    participant Google
    User->>Client: Clicks "Login" button
    Client->>API: GET /auth/client
    API->>Google: Redirect to Google Sign In
    Google->>User: Show Google Sign In page
    User->>Google: Sign In
    rect rgb(191, 223, 255)
    Google->>API: Redirect to /auth/code2jwt
    API->>Google: Exchange code for token
    Google->>API: Responds with token
    note over API: Add user info to JWT
    end
    API->>User: Redirect to client with JWT token
    User->>Client: JWT token is stored in cookie
    Client->>API: GET /api/endpoint
    API->>Client: Response with data

JWT token structure

You can inspect the content of the JWT token in your browsers developer tools. The token is stored in the authHeaders cookie. The token is a base64 encoded JSON object that contains the following:

{
  "authHeaders": {
    "token-type": "Bearer",
    "access-token": "eya.bc.123",
    "expires-in": 43200,
    "expires-at": 1677563877
  }
}

You can copy the value of "access-token" and run it through a a JWT decoder like https://jwt.io/ to decode the token and see the contents of what is stored there. Alternatively, use a base64 decoder to decode each of the . separated parts of the token and inspect the JSON data. It is often useful to do this in client applications to get the name, profile picture, or group permissions of the user that is signed in. Here are some example contents from the encoded data:

{
  "id": "10423959575911111111",
  "email": "bob.smith@hakai.org",
  "verified_email": true,
  "name": "Bob Smith",
  "given_name": "Bob",
  "family_name": "Smith",
  "link": "https://plus.google.com/10423959575911111111",
  "picture": "https://lh3.googleusercontent.com/a/AGBasdf-as1-",
  "locale": "en",
  "hd": "hakai.org",
  "groups": [
    "bob.smith@hakai.org",
    "fakeapp.editors@hakai.org",
    "fakeapp.readonly@hakai.org",
    "muckraker.team@hakai.org"
  ],
  "workareas": [
    "QUADRA",
    "LOWER MAINLAND"
  ],
  "organizations": [
    "HAKAI"
  ],
  "iat": 1677520677,
  "exp": 1677563877,
  "iss": "hakai-api"
}

Postman

Note

This section needs improvement. The following instructions work, but require authenticating outside of Postman. It would be better to have a way to authenticate without having to open a browser window.

To test the API using Goose or Hecate using the Postman application do the following:

  1. Open a browser and navigate to https://hecate.hakai.org/api-client-login
  2. Login with your Google account
  3. On the next page, copy the access_token that is displayed in the text box (Not the entire JSON object!).
    1. This text will look like token_type=Bearer&access_token=ey...&expires_at=1677570587
    2. Copy the text starting from ey up to, but not including, the &expirs_at=... part.
  4. Open Postman and, under the URL, click "Auth"
  5. Select Type: "Bearer Token"
  6. Paste the copied access token into the "Token" field
  7. You can now test this worked by making a request in Postman to https://hecate.hakai.org/api/whoami
    1. If it worked, you should see the content of your token with your name and google groups in the response.

Long-lived tokens

If you know what you're doing, you can generate a Hakai-API token that lasts for a year instead of a single day, side-stepping the need to log-in as a user every day. This is useful for allowing automatic scripts that cannot possibly run on the same server as the API and thus require an auth token. To do this:

  1. Log into the server you want a token for using ssh
  2. Navigate to the hakai-api directory
  3. Run npm run generate-token
  4. Follow the prompts and record the token that you're given for later use

It's possible to invalidate these tokens by changing the JWT_SECRET in the server's .env file in the hakai-api directory, but it may already be too late to avoid damage to our database if an attacker obtained a long-lived token. Be careful.