# Authentication

Every request to the Archipad APIs, GraphQL and REST alike, carries an OAuth 2.0 bearer token ([RFC 6750](https://www.rfc-editor.org/rfc/rfc6750)) issued by the Archipad identity provider, an OpenID Connect provider. The APIs check the token's signature against the provider's published keys, its issuer, its audience and its expiry. There are two ways to get one, depending on whether your integration acts on behalf of a person or on its own.

## Before you start

You need an OAuth client registered with Archipad: a client ID, a client secret if your integration runs on a server, and the redirect URIs of your application if people sign in through it. Ask your Archipad contact for one. The provider's endpoints are published in its discovery document ([OpenID Connect Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html)); the examples below name them as the document does.

- Issuer: `https://auth.archipad.dev/`
- Discovery document: `https://auth.archipad.dev/.well-known/openid-configuration`
- Audience: `stage.archipad-api`
- GraphQL endpoint: `https://api.archipad.dev/graphql`

## On behalf of a user

For an application a person uses: a web, mobile or desktop app, or a tool run under someone's own account. The person signs in on the identity provider and your application receives a token that identifies them; the APIs then answer what that person is allowed to see. Use the authorization code flow with PKCE ([RFC 6749](https://www.rfc-editor.org/rfc/rfc6749#section-4.1), [RFC 7636](https://www.rfc-editor.org/rfc/rfc7636)), which the [OAuth 2.0 Security Best Current Practice](https://www.rfc-editor.org/rfc/rfc9700) recommends for every kind of client. A public client, such as a browser or mobile app, has no secret at all.

1. Generate a random `code_verifier` and derive its `code_challenge` with SHA-256, base64url-encoded.
2. Send the person to the authorization endpoint. The `audience` names the APIs the token is for; the `state` is a random value you check on the way back.

   ```http
   GET <authorization_endpoint>
     ?response_type=code
     &client_id=<client-id>
     &redirect_uri=https://<your-app>/callback
     &scope=openid%20email
     &audience=stage.archipad-api
     &state=<random-state>
     &code_challenge=<S256-challenge>
     &code_challenge_method=S256
   ```

3. Once signed in, the person is redirected to your `redirect_uri` with a `code` and the `state`. Refuse the response if the state is not the one you sent.
4. Exchange the code for a token at the token endpoint, proving the verifier. A confidential client also authenticates here, as in the server-to-server request below.

   ```sh
   curl -X POST <token_endpoint> \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d grant_type=authorization_code \
     -d client_id=<client-id> \
     -d redirect_uri=https://<your-app>/callback \
     -d code=<code> \
     -d code_verifier=<code-verifier>
   ```

5. The token endpoint answers the access token and its lifetime in seconds.

   ```json
   {
     "access_token": "eyJhbGciOiJSUzI1NiIs…",
     "token_type": "Bearer",
     "expires_in": 3600
   }
   ```

## Server to server

For an integration with no person present: a backend synchronising data, a scheduled job. Your client authenticates with its own credentials and receives a token that represents it. Use the client credentials grant ([RFC 6749](https://www.rfc-editor.org/rfc/rfc6749#section-4.4)), authenticating with HTTP Basic as the standard recommends. Keep the secret on your servers: never ship it in a browser or a mobile app.

```sh
curl -X POST <token_endpoint> \
  -u "<client-id>:<client-secret>" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d grant_type=client_credentials \
  -d scope=openid \
  -d audience=stage.archipad-api
```

The answer has the same shape as above.

## Calling the APIs

Send the token in the `Authorization` header of every request, to the GraphQL API as to the REST APIs. A GraphQL query, for instance:

```sh
curl -X POST https://api.archipad.dev/graphql \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{ "query": "query { project(id: \"<project-id>\") { id name } }" }'
```

The APIs reject a request whose token is missing, expired, or issued for another audience or by another provider; it also rejects a client that is not allowed to use them, even with a valid token. Ask your Archipad contact if a valid token is refused.

## Token lifetime

A token is valid for `expires_in` seconds. Keep it and reuse it until shortly before it expires, then get a new one: do not request a token for every call. When a person's token expires, start the sign-in again, or use the refresh token if your client was granted one.

## Try it

The documentation gets a token either way with the values above filled in: sign in as an Archipad user, or enter your own client's credentials, from the **Authentication** button of the toolbar. GraphiQL, on the [GraphQL API's overview](https://docs.archipad.dev/apis/archipad-graphql) and on each operation's page, then runs queries with it before you write any code.

## Further reading

- [RFC 6749](https://www.rfc-editor.org/rfc/rfc6749), The OAuth 2.0 Authorization Framework
- [RFC 6750](https://www.rfc-editor.org/rfc/rfc6750), Bearer Token Usage
- [RFC 7636](https://www.rfc-editor.org/rfc/rfc7636), Proof Key for Code Exchange (PKCE)
- [RFC 8252](https://www.rfc-editor.org/rfc/rfc8252), OAuth 2.0 for Native Apps
- [RFC 9068](https://www.rfc-editor.org/rfc/rfc9068), JSON Web Token Profile for OAuth 2.0 Access Tokens
- [RFC 9700](https://www.rfc-editor.org/rfc/rfc9700), Best Current Practice for OAuth 2.0 Security
- [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html) and [Discovery 1.0](https://openid.net/specs/openid-connect-discovery-1_0.html)
