# Importing & exporting

unjwt functions accept keys in many shapes — `JWK`, `CryptoKey`, `Uint8Array`, password strings. Internally, everything is normalized through `importKey()`.

Import:

```ts
import { importKey, exportKey } from "unjwt/jwk";
```

## `importKey`

```ts
importKey(key, algOrOptions?)
```

Takes any supported input shape and returns a `CryptoKey` (for asymmetric JWKs) or a `Uint8Array` (for symmetric material, by default).

### Input shapes

<table>
<thead>
  <tr>
    <th>
      Input
    </th>
    
    <th>
      Output (default)
    </th>
    
    <th>
      Notes
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        Uint8Array
      </code>
      
       (UTF-8 bytes)
    </td>
    
    <td>
      Treat as a password or raw secret.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        Uint8Array
      </code>
    </td>
    
    <td>
      Same <code>
        Uint8Array
      </code>
    </td>
    
    <td>
      Returned as-is.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        CryptoKey
      </code>
    </td>
    
    <td>
      Same <code>
        CryptoKey
      </code>
    </td>
    
    <td>
      Returned as-is (subject to <code>
        expect
      </code>
      
       validation).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        JWK_oct
      </code>
    </td>
    
    <td>
      <code>
        Uint8Array
      </code>
      
       (from <code>
        k
      </code>
      
      )
    </td>
    
    <td>
      Bytes — pass <code>
        asCryptoKey: true
      </code>
      
       to get a CryptoKey.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        JWK_Public
      </code>
      
       / <code>
        JWK_Private
      </code>
      
       (asymmetric)
    </td>
    
    <td>
      <code>
        CryptoKey
      </code>
    </td>
    
    <td>
      Requires <code>
        alg
      </code>
      
       (from the JWK or explicit option).
    </td>
  </tr>
</tbody>
</table>

### The `expect` option

`expect: "public" | "private"` validates the caller's intent **before** the import runs. If the key type doesn't match, `importKey()` throws `ERR_JWK_INVALID` instead of silently succeeding:

```ts [expect.ts]
import { importKey } from "unjwt/jwk";

// Good: recipient public JWK passed with expect: "public"
const pubKey = await importKey(recipientJwk, { alg: "RSA-OAEP-256", expect: "public" });

// Will throw if somebody accidentally passed a private JWK here
```

`expect` is a no-op for symmetric JWKs and `"secret"`-type CryptoKeys — they have no public/private distinction.

<note>

`verify()` passes `expect: "public"` and `decrypt()` passes `expect: "private"` automatically. You only need `expect` when calling `importKey()` directly — which is rare; you'd typically just pass the JWK straight to `sign`/`verify`/`encrypt`/`decrypt`.

</note>

### `asCryptoKey: true` for `JWK_oct`

By default, a `JWK_oct` imports as raw bytes. Opt in to a non-extractable `CryptoKey`:

```ts [as-cryptokey.ts]
const aesCryptoKey = await importKey(symJwk, {
  asCryptoKey: true,
  algorithm: { name: "AES-GCM", length: 256 },
  usage: ["encrypt", "decrypt"],
  extractable: false, // default
});
```

Handy when you want the bytes to stay inside Web Crypto and never be retrievable.

### Full options

```ts
// For JWK_oct
interface ImportOctOptions {
  asCryptoKey: true;
  algorithm: AlgorithmIdentifier | HmacImportParams | AesDerivedKeyParams;
  usage: KeyUsage[];
  extractable?: boolean; // default false for asCryptoKey: true
}

// For asymmetric JWK
interface ImportAsymmetricOptions {
  alg?: JWSAlgorithm | KeyManagementAlgorithm; // required if JWK.alg is missing
  expect?: "public" | "private";
}
```

## `exportKey`

```ts
exportKey(key, jwkParams?)
```

Exports a `CryptoKey` as a JWK. Optionally merges metadata fields into the result.

```ts [export.ts]
import { exportKey } from "unjwt/jwk";

const cryptoKey = await crypto.subtle.generateKey(/* ... */);
const jwk = await exportKey(cryptoKey, { kid: "legacy-1", use: "sig" });
// { kty, alg, key_ops, ext, ...actual key fields, kid: "legacy-1", use: "sig" }
```

The authoritative fields (`alg`, `kty`, `key_ops`, `ext`) come from Web Crypto's export and **cannot be overridden** via `jwkParams`. Only additive metadata (`kid`, `use`, `x5c`, `x5t`, `x5u`, custom fields) is merged.

<tip>

Most of the time you won't call `exportKey()` directly — the output of `generateJWK()` is already a JWK. You'd use `exportKey()` when you've received or imported a `CryptoKey` from an external source (Web Crypto directly, another library) and need to serialize it.

</tip>

## See also

- [Generating keys →](/jwk/generating)
- [PEM conversion →](/jwk/pem) — for keys in `.pem` files.
- [JWK cache →](/jwk/cache) — `importKey` memoization.
